带管道的 Bash oneliner,如果条件给出错误

fil*_*ble 5 linux bash shell if-statement pipe

我正在尝试使用 if 条件在 bash 中查找特定进程的数量

if ps auwx | grep -v grep | grep -ic python -le 2; then echo error; else echo no_error; fi
Run Code Online (Sandbox Code Playgroud)

我得到的输出为

grep: python: No such file or directory
Run Code Online (Sandbox Code Playgroud)

没有错误

如果我使用管道,单行似乎会中断,如果我省略管道,则不会抛出任何错误,如果我使用绝对路径来 grep 也没有关系。没有管道,我无法获得所需的结果。我在这里做错了什么?我可以在脚本文件中完成此操作,方法是将其分解为变量然后进行比较,但我将其用作学习 bash 的练习。任何帮助是极大的赞赏。

ran*_*mir 6

首先,if命令的语法是:

if cmd; then
    # cmd exited with status 0 (success)
else
    # cmd exited with status >0 (fail)
fi
Run Code Online (Sandbox Code Playgroud)

cmd上面的是所谓的名单-序列管道。每个管道都是一个以|.分隔的命令序列。

-le操作者被解释通过test命令(也称为[,或[[),而不是由if命令。

所以,当你说:

if ps auwx | grep -v grep | grep -ic python -le 2; then ... fi
Run Code Online (Sandbox Code Playgroud)

你实际上grep用参数调用:

grep -ic python -le 2
Run Code Online (Sandbox Code Playgroud)

并且由于-e用于指定搜索模式,因此参数python被解释为文件的文件名以搜索模式2。这就是为什么grep告诉你它找不到名为python.

要测试一个命令管道的输出if,你可以使用命令替换里面的[[/ [/ test(如其他答案建议):

if [[ $(ps auwx | grep -v grep | grep -ic python) -le 2 ]]; then ... fi
Run Code Online (Sandbox Code Playgroud)

或者,在 内(( .. )),使用隐式算术比较:

if (( $(ps auwx | grep -v grep | grep -ic python) <= 2 )); then ... fi
Run Code Online (Sandbox Code Playgroud)

  • 稍微扩展一下:在 bash 脚本中,上下文*很重要*。在特定上下文中表示某件事的句法元素(例如`-le` 表示小于或等于内部`[ ]` 或`[[ ]]`)在其他上下文中通常意味着完全不同的东西(例如遵循`grep`命令)。`[ ]` 中的语法规则与 `[[ ]]` 中的语法规则略有不同,它与 `(( ))` 中的语法规则完全不同,这些都与 `${ } 中的有效内容没有任何关系`,并且以上所有内容都与您可以在命令行上单独使用的内容不同。 (3认同)