在 shell 脚本中,我经常使用多个管道,如下所示:
cmd1 | cmd2 | cmd3
现在,如果cmd2
缺少管道将导致“损坏”并且cmd3
不会接收任何输入。
作为解决方法,我可以显式测试 cmd2 是否存在,但这需要一些我想避免的代码复制。
相反,我想要一个更简洁的测试,如下所示:
cmd1 | cmd2; [ $? -eq 127 ] && cat | cmd3
答案1
您可以编写一个迷你函数以使其更加简洁:
ifexists(){
if command -v "$1"
then "$@"
else echo "doing cat for missing $1" >&2
cat
fi
}
echo hi | ifexists mycommand | cat -n
答案2
根据您的示例,您似乎正在寻找一种将优先级低于|
, (即&&
和||
)的操作的参数分组的方法。
{
和元}
字符可用于以这种方式进行分组。
上面的示例可以这样写(使用 的退出状态来which
确定是否cmd2
存在)。
cmd1 | { which cmd2 >/dev/null && cmd2 || cat; } | cmd3
例如
printf "hi\n" | { : && rev || cat; } | cat
会打印ih
您使用子外壳的建议也将起作用,但不必要地使用另一个进程
printf "hi\n" | ( : && rev || cat ) | cat
我想说,如果您if
在管道外部使用显式的,那么它可能不那么棘手,并且可维护性更好。
if [ which cmd2 >/dev/null ]
then
cmd1 | cmd3
else
cmd1 | cmd2 | cmd3
fi