我可以在不使用 cat 的情况下有条件地将 shell 函数作为管道 "disappear" 吗?
Can I make a shell function in as a pipeline conditionally "disappear", without using cat?
我有一个 bash 脚本,可以从命令管道中生成一些文本。基于命令行选项,我想对输出进行一些验证。举个人为的例子...
CHECK_OUTPUT=
...
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
[编辑] 更好的例子:
这真的很有用,尤其是当我有多个可以成为直通函数的函数时。是的,我可以移动 CHECK_OUTPUT 条件并创建一个有或没有 check_output 的管道,但我需要为每个组合编写行以获得更多功能。如果有更好的动态构建管道的方法我想知道。
问题是“猫的无用使用”。是否可以避免这种情况并使 check_output
就像它根本不在管道中一样?
是的,您可以这样做——通过使您的函数成为一个有条件地注入管道元素的包装器,而不是本身是一个无条件的管道元素。例如:
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'
以上代码的注意事项:如果设置了 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]*//'
我有一个 bash 脚本,可以从命令管道中生成一些文本。基于命令行选项,我想对输出进行一些验证。举个人为的例子...
CHECK_OUTPUT=
...
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
[编辑] 更好的例子:
这真的很有用,尤其是当我有多个可以成为直通函数的函数时。是的,我可以移动 CHECK_OUTPUT 条件并创建一个有或没有 check_output 的管道,但我需要为每个组合编写行以获得更多功能。如果有更好的动态构建管道的方法我想知道。
问题是“猫的无用使用”。是否可以避免这种情况并使 check_output
就像它根本不在管道中一样?
是的,您可以这样做——通过使您的函数成为一个有条件地注入管道元素的包装器,而不是本身是一个无条件的管道元素。例如:
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'
以上代码的注意事项:如果设置了 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]*//'