从这个问题扩展,我们有一个用例,我们希望根据该命令是成功还是失败来管道命令的标准输出。
我们从一个基本的管道开始
command | grep -P "foo"
但是我们注意到有时command
不会向 stdout 输出任何内容,但退出代码为0
. 我们想忽略这种情况,仅grep
在退出代码为1
对于一个工作示例,我们可以实现如下命令:
OUTPUT=$(command) # exit code is 0 or 1
RESULT=$?
if [ $RESULT -eq 0 ]; then
return $RESULT; # if the exit code is 0 then we simply pass it forward
else
grep -P "foo" <<< $OUTPUT; # otherwise check if the stdout contains "foo"
fi
但这有许多缺点,即您必须编写脚本,这意味着您不能只在控制台中执行它。也显得有些业余。
为了更简洁的语法,我正在想象一个虚构的三元运算符,如果退出代码是 ,它会通过管道1
传递,否则它会向前传递退出代码。
command |?1 grep -P "foo" : $?
是否有一系列运算符和实用程序可以实现此结果?
管道中的命令同时运行,这就是管道和进程间通信机制的全部意义所在。
在:
cmd1
并cmd2
同时启动,对写入cmd2
的数据进行处理cmd1
。如果您只想
cmd2
在cmd1
失败时启动cmd2
,cmd1
则必须在完成并报告其退出状态后启动,因此您不能使用管道,您必须使用保存所有数据的临时文件cmd1
产生了:或者像在您的示例中那样存储在内存中,但是还有许多其他问题(例如
$(...)
删除所有尾随换行符,并且大多数 shell 无法处理其中的 NUL 字节,更不用说大型输出的缩放问题了)。在 Linux 上,使用类似
zsh
或bash
将 here-documents 和 here-strings 存储在临时文件中的 shell,您可以执行以下操作:让外壳处理临时文件的创建和清理。
bash 版本 5 现在在创建临时文件后删除了对临时文件的写入权限,因此上述方法不起作用,您需要先恢复写入权限来解决它:
手动,POSIXly:
一些系统有一个非标准
mktemp
命令(尽管系统之间的接口有所不同),这使得临时文件的创建更容易一些(tmpfile=$(mktemp)
对于大多数实现来说应该足够了,尽管有些不会创建文件,所以你可能需要调整umask
)。兼容的实现[ -n "$tmpfile" ]
应该不需要m4
,但 GNU至少不兼容,因为它在调用失败m4
时不会返回非零退出状态。mkstemp()
另请注意,没有什么可以阻止您在控制台中运行任何代码。您的“脚本”可以在交互式外壳的提示下输入相同的内容(
return
假设代码在函数中的部分除外),但您可以将其简化为:注意:由于问题被标记为bash,我假设您可以使用 bash 功能。
鉴于您的示例代码,您似乎想要做的是:
grep
' 退出状态。在空管道上运行
grep
不会花费您任何费用,因此一种选择是无论如何都要通过管道传输它,并检查命令的退出状态,您可以使用PIPESTATUS
bash 中的数组来获取它:这里,subshell 以 1 退出,grep 以 0 退出。
因此,您可以执行以下操作:
表达式可以简化,但你明白了。
还可以选择简单地伪造输出:
where
echo foo
仅当命令成功时才会运行,从而使 grep 也成功。