我正在尝试检测进程 ( goland.sh
) 是否正在运行。我用过这个:
#!/bin/bash
if pgrep "goland.sh" >/dev/null 2>&1 ; then
echo "running"
exit 1
fi
echo "not running"
这可行,但我不明白两件事:
- 为什么如果我使用
if [[ pgrep "goland.sh" >/dev/null 2>&1 ]] ; then
它不起作用(即使进程没有运行它总是打印“正在运行”) - 为什么如果我使用
if [ pgrep "goland.sh" >/dev/null 2>&1 ] ; then
它不起作用(即使进程没有运行它总是打印“正在运行”)
我怀疑 1 与如何解析有关>
,但我对 2 完全一无所知。
答案1
似乎对 shell 的测试构造[ ... ]
(或[[ ... ]]
Bash 的情况)如何工作存在误解。
- 该
if
语句检查其后面的命令是否返回退出状态0
,这意味着“无错误”并被解释为“true”。如果是这样,执行将切换到then
脚本的分支(请参阅Bash 手册例如)。 - 如果该命令找到与该模式匹配的进程,则该
pgrep
命令返回(即“true”)。这就是为什么只有当 的实例处于活动状态时才会0
得到。running
goland.sh
- 这
[
是一个特殊的命令(通常是 shell 内置命令),允许对文件、字符串和数字执行测试,如果左括号和右括号之间的条件为 true,则返回“true”。然而,它被设计为根据特定语法检查对一个或多个操作数的操作是否为真,例如,一个数字(操作数1)是否大于(运算符)另一个数字(操作数2)。例如,假设 shell 变量n
的值为5
,则测试
将返回true,当用作语句的测试命令时[ "$n" -gt 5 ]
if
,执行将切换到then
分支。 - 定义了几个测试结构,以便您可以检查例如字符串是否为空,文件是否存在和/或可执行等。但是,在所有情况下,您都必须了解之间代码的正确语法
[ ... ]
以确保你得到预期的结果。
现在,您已在测试构造括号内包含了一个“原始”shell 命令。然后发生的情况在某种程度上取决于具体情况,但无论如何,它都会构成语法错误,因为方括号之间有多个(常量)字符串标记,而没有有效的运算符。
- 使用 时,
[[ ... ]]
您将立即收到语法错误,因为它是 Bash 语法元素,并且 Bash 识别出错误的语法。 - 但是,如果出现这种情况,
[ ... ]
您的命令将默默失败,因为[
实际上是命令(尽管通常是内置的),它只是碰巧期望其参数对于预定义的运算符有意义,并期望其最后一个参数是结束参数]
- 但由于您已将其错误输出重定向到/dev/null
,错误消息将丢失。 running
无论哪种情况,我都无法用错误的语法重现您总是得到的输出。
总而言之,您不需要使用[ ... ]
(或[[ ... ]]
) 构造,因为如果找到正在运行的进程,您用于测试的程序已经返回“true”。如果您想将测试基于输出,pgrep
您需要使用“命令替换” $(pgrep ...)
(当然还要删除到 的输出重定向/dev/null
)。
我建议检查你的 shell 脚本shellcheck
,也可以在许多 Linux 发行版上作为独立程序使用,以防止语法(和一些逻辑)错误。