【问题标题】:Different results between ps aux and `ps aux` inside a script脚本中 ps aux 和 `ps aux` 的结果不同
【发布时间】:2016-01-02 14:46:32
【问题描述】:

我有一个 bash 脚本 (ScreamDaemon.sh),其中添加了一个检查它的示例尚未运行。

numscr=`ps aux | grep ScreamDaemon.sh | wc -l`;
if [ "${numscr}" -gt "2" ]; then
  echo "an instance of ScreamDaemon still running";
  exit 0;
fi

通常,如果没有其他脚本正在运行,ps aux | grep ScreamDaemon.sh | wc -l 应该返回 2(它应该找到自己和 grep ScreamDaemon.sh),但它返回 3。

所以,我尝试分析发生了什么,并在添加一些回声后看到:

我在脚本中添加了几行

ps aux | grep ScreamDaemon.sh
ps aux | grep ScreamDaemon.sh | wc -l
str=`ps aux | grep ScreamDaemon.sh`
echo $str
numscr=`ps aux | grep ScreamDaemon.sh | wc -l`;
echo $numscr

有一个输出:

pamela   27894  0.0  0.0 106100  1216 pts/1    S+   13:41   0:00 /bin/bash ./ScreamDaemon.sh
pamela   27899  0.0  0.0 103252   844 pts/1    S+   13:41   0:00 grep ScreamDaemon.sh
2
pamela 27894 0.0 0.0 106100 1216 pts/1 S+ 13:41 0:00 /bin/bash ./ScreamDaemon.sh pamela 27903 0.0 0.0 106100 524 pts/1 S+ 13:41 0:00 /bin/bash ./ScreamDaemon.sh pamela 27905 0.0 0.0 103252 848 pts/1 S+ 13:41 0:00 grep ScreamDaemon.sh
3

我还尝试在 `ps aux | 中添加 sleep 命令。 grep ScreamDaemon.sh; sleep 1m` 并从并行终端查看 ps aux|grep ScreamDaemon.sh 显示了多少实例:

[pamela@pm03 ~]$ ps aux | grep ScreamDaemon.sh
pamela   28394  0.0  0.0 106100  1216 pts/1    S+   14:23   0:00 /bin/bash ./ScreamDaemon.sh
pamela   28403  0.0  0.0 106100   592 pts/1    S+   14:23   0:00 /bin/bash ./ScreamDaemon.sh
pamela   28408  0.0  0.0 103252   848 pts/9    S+   14:23   0:00 grep ScreamDaemon.sh

看来, str=`ps 辅助 | grep ScreamDaemon.sh` 与之相反 ps辅助| grep ScreamDaemon.sh 找到了 ScreamDaemon.sh 的两个实例,但为什么呢? ScreamDaemon.sh 的这个额外副本来自哪里?

这是 pstree -ap 命令的输出

  │   ├─sshd,27806
  │   │   └─sshd,27808
  │   │       └─bash,27809
  │   │           └─ScreamDaemon.sh,28731 ./ScreamDaemon.sh
  │   │               └─ScreamDaemon.sh,28740 ./ScreamDaemon.sh
  │   │                   └─sleep,28743 2m

【问题讨论】:

  • 它从搜索结果中排除了 grep ScreamDaemon.sh,但它仍然找到 2 个实例而不是 1跨度>
  • 你能输入并粘贴pstree -ap 的输出吗? (你可以剪掉不需要的线条)
  • 找不到如何将其以可读形式放在这里的方法:(
  • 所以,像这样:sshd,27806->sshd,27808->bash,27809->ScreamDaemon.sh,28731 ./ScreamDaemon.sh->ScreamDaemon.sh,28740 ./ScreamDaemon.sh->sleep,28743 2m
  • 把这个放在原文中

标签: linux bash shell


【解决方案1】:

为什么一个 bash 脚本会在 ps 中出现多次?

当任何隐式创建子外壳的结构在起作用时,这很典型。例如,在 bash 中:

echo foo | bar

...创建一个新的 shell 分叉副本以运行 echo,并带有自己的 ps 实例。同样:

( bar; echo done )

...创建一个新的子shell,让该子shell 运行外部命令bar,然后让子shell 执行echo。

同样:

foo=$(bar)

...为命令替换创建一个子shell,在其中运行bar(可能exec'ing 命令并使用子shell,但这不能保证),并将其输出读入父级。

现在,这如何回答您的问题?因为

result=$(ps aux | grep | wc)

...在子shell 中运行ps 命令,它本身会创建一个额外的bash 实例。


如何正确确保我的脚本只有一个副本在运行?

使用锁定文件。

例如:

请注意,我强烈建议使用基于 flock 的变体。

【讨论】:

    【解决方案2】:

    当然,你之所以找到额外的流程是因为:

    一个进程正在运行子shell(命令执行`..`)
    包含在您的行中:numscr=`ps aux | grep ScreamDaemon.sh | wc -l`;

    这是最简单的答案。


    不过,我想对您的代码提出一些额外的建议:

    首先,引用你的扩展,它应该是:echo "$str"。
    不这样做会使几行折叠成一条长的。

    其次,您可以使用:grep [S]creamDaemon.sh 来避免匹配 grep 命令本身。

    第三,在变量中只捕获一次命令,然后从变量中计算行数。在这种情况下,它没有问题,但对于动态过程,一次捕获和随后的捕获计数可能会产生不同的结果。

    第四,养成使用$(...)command substitutions而不是更容易出错(尤其是嵌套时)`...`的习惯。

    ### Using a file as the simplest way to capture the output of a command
    ### that is running in this shell (not a subshell).
    ps aux | grep "[S]creamDaemon.sh" > "/tmp/tmpfile$$.txt"  
    
    str="$(< "/tmp/tmpfile$$.txt")"                ### get the value of var "str"
    rm "/tmp/tmpfile$$.txt"                        ### erase the file used ($$ is pid).
    
    numscr="$(echo "$str" | wc -l)"                ### count the number of lines.
    echo "$numscr"                                 ### present results.
    echo "$str"
    
    str="$( ps aux | grep "[S]creamDaemon.sh" )"   ### capture var "str".
    numscr="$(echo "$str" | wc -l)"                ### count the number of lines.
    echo "$numscr"                                 ### present results.
    echo "$str"
    
    ### The only bashim is the `$(<...)`, change to `$(cat ...)` if needed.
    

    @CharlesDuffy 很好地涵盖了flock 的观点,please read it。

    【讨论】:

    • 可能还提到pgrep——如果可用,最好是ps | grep 成语。
    • -f 参数匹配完整的命令行;因此:pgrep -f ScreamDaemon.sh
    猜你喜欢
    • 2013-02-12
    • 2022-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 2019-08-20
    • 2019-03-29
    相关资源
    最近更新 更多