【问题标题】:Continue script if only one instance is running? [duplicate]如果只有一个实例正在运行,是否继续执行脚本? [复制]
【发布时间】:2011-02-01 13:46:29
【问题描述】:

现在这很尴尬。我正在编写快速脚本,但我无法弄清楚为什么这个语句不起作用。

if [ $(pidof -x test.sh | wc -w) -eq 1 ]; then echo Passed; fi

我也尝试使用反引号代替 $(),但它仍然不起作用。

你能看出它有什么问题吗? pidof -x test.sh | wc -w 如果我在脚本中运行它会返回 1,所以我看不出有任何理由说明 if [ 1 -eq 1 ] 基本上不会通过。

非常感谢!

【问题讨论】:

  • 最好总是在测试中引用表达式,以防它们变成空字符串。不过,在这种情况下,我很确定wc -w 肯定会打印一些东西?安全总比后悔好。
  • 你能在 if 之外回显它以检查它打印的内容吗?看看它不工作是因为它是零,还是因为它是两个?
  • @pajton:我认为这有点像产生同名子进程的愚蠢行为——这是在我们可以看到的代码之外完成的。
  • @Jefromi:我没有比我在问题中写的更多的代码。

标签: bash if-statement


【解决方案1】:

Jefromi 是正确的;这是我认为你想要的逻辑:

#!/bin/bash
# this is "test.sh"

if [ $(pidof -x test.sh| wc -w) -gt 2 ]; then 
    echo "More than 1"
    exit
fi

echo "Only one; doing whatever..."

【讨论】:

  • 这个问题是它不会在你的代码中到处工作——如果你把它放在一个循环结构中,它也会创建一个子shell,你会得到三个计数。把它放在另一个循环中,四个计数。
  • 是的。但是,如果它应该是在脚本开始时进行的简单检查,而您一次只希望运行一个实例,那么这是干净且有效的。什么会更好(真诚的问题)?
  • 凯文写的在这种情况下是一个原因。但是你能解释一下,为什么 wc(以及 awk 字段计数)返回 n+1 吗?如果我echo $(pidof -x test.sh) > wc.txt 然后wc -w wc.txt 它正确返回1 wc.txt
  • 一个锁文件。请参阅 Chris Johnsen 对我的回答的评论 - 这是一个非常简单的情况,它们都是相同的脚本,但一般来说,只要您可以编辑所有代码,您就可以设置一个锁来获取你想要的行为!
  • -gt 表示大于。所以-gt 2 = more than 2 (3, 4, 5, 6 ... n),而不是more than 1
【解决方案2】:

啊,真正的答案:当您使用管道时,您会强制创建子外壳。这总是会导致您获得更多的数字:

#!/bin/bash

echo "subshell:"
np=$(pidof -x foo.bash | wc -w)
echo "$np processes"   # two processes

echo "no subshell:"
np=$(pidof -x foo.bash)
np=$(echo $np | wc -w)
echo "$np processes"   # one process

老实说,我不确定最快捷的方法是做你真正想做的事。您可以通过创建一个锁定文件来避免这一切 - 否则您可能必须通过 ppid 追溯到所有顶级进程并计算它们。

【讨论】:

  • 感谢您的回答。玩弄你的例子,我发现我的脚本的问题实际上是脚本的wc -w 部分而不是子shell 产生。它返回 n+1,这很有趣。
  • @Andrew: 呃,wc -w 绝对算对了。试试“echo 1352 | wc -w”,你可以很容易地看到它把一个pid算作一个词。
  • 由于所有参与者都可以合作(它们是同一脚本的实例),因此锁定文件似乎是可行的方法。我喜欢 procmail 包中的 lockfile linux.die.net/man/1/lockfile procmail.org
  • @Jefromi 就像我在凯文的回答评论中所说,当我将pidof 输出重定向到文件然后在该文件上使用wc -w 时,它会正确返回1。如果我使用pidof test.sh | wc -w,它会返回2 ...
  • @Andrew:是的,当您使用管道时,您正在生成子外壳,但在使用重定向时不会。再读一遍我的答案。
【解决方案3】:

你不必将 pidof 的结果传递给 wc 来计算有多少..使用 shell

r=$(pidof -x -o $$ test.sh)
set -- $r
if [ "${#@}" -eq 1 ];then
 echo "passed"
else
 echo "no"
fi

【讨论】:

    【解决方案4】:

    如果您使用 -o 选项省略脚本的 PID ($$),则只会考虑子 shell 的 PID 和脚本的任何其他实例(以及它们可能产生的任何子 shell),所以只有一个实例时测试会通过:

    if [ $(pidof -x -o $$ test.sh | wc -w) -eq 1 ]; then echo Passed; fi
    

    【讨论】:

      【解决方案5】:

      我会这样做:

      if [ "`pgrep -c someprocess`" -gt "1" ]; then
        echo "More than one process running"
      else
        echo "Multiple processes not running"
      fi
      

      【讨论】:

        【解决方案6】:

        如果你不想使用锁文件...你可以试试这个:

        #!/bin/bash
        
        if [[ "$(ps -N -p $$ -o comm,pid)" =~ $'\n'"${0##*/}"[[:space:]] ]]; then
            echo "aready running!"
            exit 1
        fi
        

        PS:它可能需要调整一个奇怪的 ${0##*/}

        【讨论】:

          【解决方案7】:

          只需检查是否存在任何一个(或多个)标识为 test.sh 的进程,如果没有找到则返回码为 1:

          pidof -x test.sh >/dev/null && echo "Passed"
          

          【讨论】:

            猜你喜欢
            • 2016-06-08
            • 2010-12-15
            • 2011-01-15
            • 2018-04-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-24
            相关资源
            最近更新 更多