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

Dea*_*ean 0 bash test

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

#!/bin/bash

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

echo "not running"
Run Code Online (Sandbox Code Playgroud)

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

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

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

Adm*_*Bee 10

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

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

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

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

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

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