如果我使用 [[ 或 [,“if pgrep”将不再起作用

如果我使用 [[ 或 [,“if pgrep”将不再起作用

我正在尝试检测进程 ( goland.sh) 是否正在运行。我用过这个:

#!/bin/bash

if pgrep "goland.sh" >/dev/null 2>&1 ; then
    echo "running"
    exit 1
fi

echo "not running"

这可行,但我不明白两件事:

  1. 为什么如果我使用if [[ pgrep "goland.sh" >/dev/null 2>&1 ]] ; then它不起作用(即使进程没有运行它总是打印“正在运行”)
  2. 为什么如果我使用if [ pgrep "goland.sh" >/dev/null 2>&1 ] ; then它不起作用(即使进程没有运行它总是打印“正在运行”)

我怀疑 1 与如何解析有关>,但我对 2 完全一无所知。

答案1

似乎对 shell 的测试构造[ ... ](或[[ ... ]]Bash 的情况)如何工作存在误解。

  • if语句检查其后面的命令是否返回退出状态0,这意味着“无错误”并被解释为“true”。如果是这样,执行将切换到then脚本的分支(请参阅Bash 手册例如)。
  • 如果该命令找到与该模式匹配的进程,则该pgrep命令返回(即“true”)。这就是为什么只有当 的实例处于活动状态时才会0得到。runninggoland.sh
  • [是一个特殊的命令(通常是 shell 内置命令),允许对文件、字符串和数字执行测试,如果左括号和右括号之间的条件为 true,则返回“true”。然而,它被设计为根据特定语法检查对一个或多个操作数的操作是否为真,例如,一个数字(操作数1)是否大于(运算符)另一个数字(操作数2)。例如,假设 shell 变量n的值为5,则测试
    [ "$n" -gt 5 ]
    
    将返回true,当用作语句的测试命令时if,执行将切换到then分支。
  • 定义了几个测试结构,以便您可以检查例如字符串是否为空,文件是否存在和/或可执行等。但是,在所有情况下,您都必须了解之间代码的正确语法[ ... ]以确保你得到预期的结果。

现在,您已在测试构造括号内包含了一个“原始”shell 命令。然后发生的情况在某种程度上取决于具体情况,但无论如何,它都会构成语法错误,因为方括号之间有多个(常量)字符串标记,而没有有效的运算符。

  • 使用 时,[[ ... ]]您将立即收到语法错误,因为它是 Bash 语法元素,并且 Bash 识别出错误的语法。
  • 但是,如果出现这种情况,[ ... ]您的命令将默默失败,因为[实际上是命令(尽管通常是内置的),它只是碰巧期望其参数对于预定义的运算符有意义,并期望其最后一个参数是结束参数]- 但由于您已将其错误输出重定向到/dev/null,错误消息将丢失。
  • running无论哪种情况,我都无法用错误的语法重现您总是得到的输出。

总而言之,您不需要使用[ ... ](或[[ ... ]]) 构造,因为如果找到正在运行的进程,您用于测试的程序已经返回“true”。如果您想将测试基于输出pgrep您需要使用“命令替换” $(pgrep ...)(当然还要删除到 的输出重定向/dev/null)。

我建议检查你的 shell 脚本shellcheck,也可以在许多 Linux 发行版上作为独立程序使用,以防止语法(和一些逻辑)错误。

相关内容