我有一些带有 grep 版本 2.16 的 SLES 12 SP5 机器,并且在一台机器上我大量使用包含以下grep --quiet条件的脚本:
# $pid_list contains the result of pstree and $script_pid equals $$
if echo "$pid_list" | grep -qF "($script_pid)"; then
continue
fi
if echo "$pid_list" | grep -qF "($script_pid)"; then
echo "Error: grep has a bug!"
continue
fi
Run Code Online (Sandbox Code Playgroud)
我将其加倍,因为第一个条件失败的概率约为 0.1%,而第二个相同条件成功?!
按如下方式更改条件后,它可以完美运行(完整代码此处):
if echo "$pid_list" | grep -F "($script_pid)" >/dev/null; then
continue
fi
Run Code Online (Sandbox Code Playgroud)
关于手册,该quiet选项的行为应该符合我的预期。如果发生错误,它甚至应该返回 true:
如果发现任何匹配,即使检测到错误,也会立即以零状态退出
所以我很困惑为什么有时会失败。机器的 RAM 和文件系统都很好。grep 二进制文件也具有正确的文件哈希值。
我搜索了一个提交,但我找到的唯一一个是2001 年的,它应该是2.16 的一部分,因为它是 2014 年的。
更新1
我尝试按照@kamil的建议使用子shell,但它仍然失败(有时会显示“竞争条件”错误):
if (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
continue
elif (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
echo "Error: Race condition!"
continue
fi
Run Code Online (Sandbox Code Playgroud)
相反,这有效:
if echo "$pid_list" | grep -qF "($script_pid)" || [[ $? -eq 141 ]]; then
continue
fi
Run Code Online (Sandbox Code Playgroud)
Kam*_*ski 13
假设:在您执行的脚本中set -o pipefail(如果解释脚本的 shell 是 Bash;其他 shell 可能提供类似的功能)。从man 1 bash:
\n\n\n
pipefail
\n如果设置,管道的返回值是最后一个(最右边)以非零状态退出的命令的值,如果管道中的所有命令都成功退出,则返回值为零。默认情况下禁用此选项。
当有匹配时,grep -q提前退出并返回0。然后echo 可能会回来,也可能不会回来141。这取决于在关闭管道末端echo之前是否设法将所有内容写入管道缓冲区。grep即使对于相同的输入,事情也可能会以一种方式或另一种方式发生,这是一种竞争条件。如果141发生这种情况,那么管道的返回值将是141因为pipefail。
假设你真的使用过,我说你观察到的行为绝对不是shellset -o pipefail的错误。grep该错误在您的脚本中。
我在链接问题下的回答提供了解决方案。对你来说最简单的一种是:
\nif (/bin/echo "$pid_list"; true) | grep -qF "($script_pid)"; then\nRun Code Online (Sandbox Code Playgroud)\n或者
\nif ((echo "$pid_list"); true) | grep -qF "($script_pid)"; then\nRun Code Online (Sandbox Code Playgroud)\n为什么/bin/echo \xe2\x80\xa6或(echo \xe2\x80\xa6)代替echo?因为你的echoshell 很可能是内置的,当“它”收到 SIGPIPE 时,那么它实际上是整个子 shell 收到 SIGPIPE 并被杀死。我们不希望应该执行的子 shelltrue被杀死。请参阅这个答案的开头。
检查整个脚本;其他条件也可能以同样的方式出现问题。
\n