Linux 脚本中ps aux和`ps aux`之间的不同结果

Linux 脚本中ps aux和`ps aux`之间的不同结果,linux,bash,shell,Linux,Bash,Shell,我有一个bash脚本(creamdaemon.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应该

我有一个bash脚本(creamdaemon.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
我还尝试将sleep命令添加到`ps aux|grep ScreamDaemon.sh;休眠1m`并从并行终端查看有多少实例显示:

[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 aux|grep.sh` 违背 ps aux| grep.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
为什么单个bash脚本可以在
ps
中多次显示? 当隐式创建子shell的任何构造都在运行时,这是典型的。例如,在bash中:

echo foo | bar
…创建shell的新分叉副本,以使用其自己的
ps
实例运行
echo
。同样地:

( bar; echo done )
foo=$(bar)
…创建一个新的子shell,让该子shell运行外部命令
bar
,然后让该子shell执行
echo

同样地:

( bar; echo done )
foo=$(bar)
…为命令替换创建子shell,在其中运行
bar
(可能执行命令并使用子shell,但这不是保证),并将其输出读入父级

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

result=$(ps aux | grep | wc)
…在子shell中运行
ps
命令,它本身会创建一个额外的bash实例


如何正确地确保只有一个脚本副本正在运行? 使用锁定文件

例如,见:


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

当然,您找到附加流程的原因是:

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

这是最简单的答案


但是,我想对您的代码提出一些其他建议:

首先,引用您的扩展,它应该是:
echo“$str”

如果不这样做,则会使多条线折叠成一条长线

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

第三,在一个变量中只捕获一次命令,然后计算变量中的行数。在这种情况下,这没有问题,但对于动态流程,一次捕获和接下来的捕获计数可能会给出不同的结果

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

### 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.
####使用文件作为捕获命令输出的最简单方式
###在这个shell(不是子shell)中运行的。
ps aux | grep“[S]creamDaemon.sh”>“/tmp/tmpfile$$.txt”
str=“$(<”/tmp/tmpfile$$.txt”)###获取var“str”的值
rm“/tmp/tmpfile$$.txt”####删除使用的文件($$是pid)。
numsr=“$(echo“$str”| wc-l)”###计算行数。
回显“$numscr”####显示结果。
回显“$str”
str=“$(ps aux | grep”[S]creamDaemon.sh”)”###capture var“str”。
numsr=“$(echo“$str”| wc-l)”###计算行数。
回显“$numscr”####显示结果。
回显“$str”

###唯一的bashim是“$”(它从搜索结果中排除了grep ScreamDaemon.sh,但它仍然找到了2个实例,而不是1个您可以键入并粘贴回
pstree-ap
?(您可以删除不需要的行)找不到一种方法如何将其以可读的形式放在这里:(因此,类似这样的东西:
sshd,27806->sshd,27808->bash,27809->creamdaemon.sh,28731./creamdaemon.sh->creamdaemon.sh,28740./creamdaemon.sh->sleep,287432m
将其放在原始消息中可能还会提到
pgrep
——如果可用,最好使用
ps|grep
习惯用法。
-f
参数再次匹配。)st完整的命令行;因此:
pgrep-f ScreamDaemon.sh