我可以在不使用 cat 的情况下将 shell 函数作为管道有条件地“消失”吗?

joz*_*yqk 2 bash shell pipe cat

我有一个 bash 脚本,它从命令管道中生成一些文本。基于命令行选项,我想对输出进行一些验证。对于一个人为的例子......

CHECK_OUTPUT=$1
...
check_output()
{
    if [[ "$CHECK_OUTPUT" != "--check" ]]; then
        # Don't check the output. Passthrough and return.
        cat
        return 0
    fi

    # Check each line exists in the fs root
    while read line; do
        if [[ ! -e "/$line" ]]; then
            echo "Error: /$line does not exist"
            return 1
        fi
        echo "$line"
    done
    return 0
}

ls /usr | grep '^b' | check_output
Run Code Online (Sandbox Code Playgroud)

[编辑] 更好的例子:https : //stackoverflow.com/a/52539364/1888983

这真的很有用,特别是如果我有多个可以成为直通的函数。是的,我可以移动 CHECK_OUTPUT 条件并创建一个带有或不带有 check_output 的管道,但我需要为每个组合编写行以获得更多功能。如果有更好的方法来动态构建管道,我想知道。

问题是“猫的无用使用”。可以避免这种情况并使其check_output完全不在管道中吗?

Cha*_*ffy 5

是的,您可以做到这一点——通过使您的函数成为有条件注入管道元素的包装器,而不是成为无条件管道元素本身。例如:

maybe_checked() {
  if [[ $CHECK_OUTPUT != "--check" ]]; then
    "$@" # just run our arguments as a command, as if we weren't here
  else
    # run our arguments in a process substitution, reading from stdout of same.
    # ...some changes from the original code:
    #   IFS= stops leading or trailing whitespace from being stripped
    #   read -r prevents backslashes from being processed
    local line # avoid modifying $line outside our function
    while IFS= read -r line; do
      [[ -e "/$line" ]] || { echo "Error: /$line does not exist" >&2; return 1; }
      printf '%s\n' "$line"  # see https://unix.stackexchange.com/questions/65803
    done < <("$@")
  fi
}

ls /usr | maybe_checked grep '^b'
Run Code Online (Sandbox Code Playgroud)

上面代码的警告:如果pipefail设置了该选项,您将需要检查进程替换的退出状态,以与否则会出现的行为完全相同。在 bash 版本 4.3 或更高版本 (IIRC) 中,$?通过进程替换修改为具有相关的 PID,可wait用于检索退出状态。

也就是说,这也是一个cat可以接受使用的用例,我是作为 UUOC 人群中的持卡成员这么说的。:)


采用 John Kugelman 对链接问题的回答中的示例:

maybe_sort() {
    if (( sort )); then
        "$@" | sort
    else
        "$@"
    fi
}

maybe_limit() {
    if [[ -n $limit ]]; then
        "$@" | head -n "$limit"
    else
        "$@"
    fi
}

printf '%s\n' "${haikus[@]}" | maybe_limit maybe_sort sed -e 's/^[ \t]*//'
Run Code Online (Sandbox Code Playgroud)