Linux Bash脚本错误地计算自身的实例

Linux Bash脚本错误地计算自身的实例,linux,bash,grep,ps,Linux,Bash,Grep,Ps,我已经创建了一个bash脚本,它统计自身启动的实例 在这里(在这个例子中,我展示的是实例,而不是用wc-l)计算它们): (当然,我的脚本名为count\u本身。sh) 执行时,我希望它返回两行,但它返回三行: root@myserver:/# ./count_itself.sh root 16225 0.0 0.0 12400 1176 pts/0 S+ 11:46 0:00 /bin/bash ./count_itself.sh root 16226 0

我已经创建了一个
bash
脚本,它统计自身启动的实例

在这里(在这个例子中,我展示的是实例,而不是用
wc-l
)计算它们):

(当然,我的脚本名为
count\u本身。sh

执行时,我希望它返回两行,但它返回三行:

root@myserver:/# ./count_itself.sh
root    16225   0.0 0.0 12400   1176 pts/0  S+  11:46   0:00    /bin/bash ./count_itself.sh
root    16226   0.0 0.0 12408   564 pts/0   S+  11:46   0:00    /bin/bash ./count_itself.sh
root    16228   0.0 0.0 11740   932 pts/0   S+  11:46   0:00    grep count_itself.sh
使用
&
标志执行时(即在后台,手动执行
ps-aux
位),它返回两个,这就是我想要的:

root@myserver:/# ./count_itself.sh &
[1] 16233
root@myserver:/# ps -aux | grep count_itself.sh
root     16233  0.0  0.0  12408  1380 pts/0    S    11:48   0:00 /bin/bash ./count_itself.sh
root     16240  0.0  0.0  11740   944 pts/0    S+   11:48   0:00 grep --color=auto count_itself.sh
我的问题是:为什么脚本中执行的
ps-aux
比预期多返回一行?

或者,换句话说,为什么在我的第一个示例中创建id为
16226
的进程

编辑(大多数人似乎误解了我的问题):

我想知道为什么执行
bash
会返回两个
/bin/bash./count\u本身.sh的实例,而不是为什么它返回
grep count\u本身.sh

编辑2:


当然,我正在寻找一种方法来避免这种行为,并让脚本只返回
/bin/bash./count_本身.sh
一次。

这是
grep
ps
输出的标准问题

一种解决方案是在字符周围添加一些方括号

nb=$(ps -aux | grep '[c]ount_itself.sh')
这意味着您的
grep
实例本身不匹配,因为进程名称及其参数包含方括号,但它匹配的模式不匹配

正如注释中提到的,应该在变量周围使用双引号以保留空格


结果中出现两个相同shell实例的原因是命令替换在子shell中执行。有关仅显示父进程的详细信息,请参阅。

进程替换要求父shell启动子shell,即在子shell中分叉并执行指定的命令。这是必需的,这样父shell就不会受到
$(…)
中包含的脚本对环境(变量、当前工作目录、陷阱)所做的任何更改的影响

例如:

$ cat test.sh 
#!/bin/bash

a=1
b="$(a=2; echo abc)"
echo "a=$a"
echo "b=$b"
$ ./test.sh 
a=1           # Note that the variable 'a' preserved its value
b=abc
分叉的结果是,您看到了脚本的一个额外实例

我认为不可能从输出中可靠地消除这些不需要的进程,因为原则上,脚本可以合法地启动自身的另一个实例(将作为子进程运行),而您无法区分这两种情况

一种黑客解决方案是让脚本在调用时在指定位置(例如在
/tmp/your_script\u name
中)创建一个PID文件,并在终止时将其删除。

我建议下一种方法:

排除父进程为我的所有进程:

 ps --pid $$ -N -a | grep count_itself.sh

这意味着显示所有父级不是我的命令(因此这不包括执行反句子的grep进程和fork进程)

最终找到了一种方法,尽管这是一种丑陋的方法,部分灵感来自于他的链接中的问题@TomFenech:

执行:

root@myserver:/# ./count_itself.sh
17725 pts/1    S+     0:00  \_ /bin/bash ./count_itself.sh
在bg中已运行一个的情况下执行:

root@myserver:/# ./count_itself.sh &
[1] 17733
root@myserver:/# ./count_itself.sh
17733 pts/1    S      0:00  \_ /bin/bash ./count_itself.sh
17739 pts/1    S+     0:00  \_ /bin/bash ./count_itself.sh
解释(据我所知):

  • ps f
    返回活动进程树
  • grep'[c]count\u本身.sh'
    将上一个命令限制为仅显示
    count\u本身.sh的实例
返回

17808 pts/1    S+     0:00  \_ /bin/bash ./count_itself.sh
17809 pts/1    S+     0:00      \_ /bin/bash ./count_itself.sh
  • grep-v'\\\\\\\'
    排除包含4个空格(相当于一个制表符)的行,然后排除对应于子流程的行

    • `ps-aux | grep count_本身。sh`
      在子shell中执行,即在子进程中。因此,执行脚本的shell被分叉,子shell然后运行
      ps-aux | grep count_本身。sh
      命令。我建议:nb=`ps-aux | grep[c]当你执行
      ps-aux | grep count_本身时。sh
      你的grep像count_本身一样进行计数。你需要提高自己regex@Leon但是显示两次的行是
      /bin/bash./count_本身.sh
      ,而不是
      ps-aux | grep count_本身.sh
      @Cyrus?这应该做什么?它返回相同的结果我编辑了我的问题,有没有办法让<代码> PS-AUX <代码>不返回子shell执行?编辑添加一个链接。它仍然回响两行,只有<代码> -PID $ $/COD>标志,如果我添加了<代码> -n>代码>标志,它什么也没回响。我在中间寻找一个结果:PI猜如果用<代码> -n>代码>标志是R。eturning nothing这是因为您是唯一正在运行的实例,如果您想计算自己,可以在结果中添加1。
      root@myserver:/# ./count_itself.sh &
      [1] 17733
      root@myserver:/# ./count_itself.sh
      17733 pts/1    S      0:00  \_ /bin/bash ./count_itself.sh
      17739 pts/1    S+     0:00  \_ /bin/bash ./count_itself.sh
      
      17808 pts/1    S+     0:00  \_ /bin/bash ./count_itself.sh
      17809 pts/1    S+     0:00      \_ /bin/bash ./count_itself.sh