我创建了一个bash
脚本,用于计算已启动的实例。
这是(在这个例子中,我是显示实例而不是用wc -l
计算它们):
#!/bin/bash
nb=`ps -aux | grep count_itself.sh`
echo "$nb"
sleep 20
(当然,我的脚本名为count_itself.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
执行会比预期更多地返回一行?
或者,换句话说,为什么在我的第一个示例中创建了标识16226
的流程?
编辑(因为大多数人似乎误解了我的问题):
我想知道为什么bash
执行返回/bin/bash ./count_itself.sh
的两个实例,而不是它返回grep count_itself.sh
的原因。
编辑2:
当然,我正在寻找一种避免此行为的方法,并让脚本只返回/bin/bash ./count_itself.sh
一次。
答案 0 :(得分:4)
这是list
grep
输出的标准问题。
一种解决方案是在角色周围添加一些方括号
ps
这意味着您的nb=$(ps -aux | grep '[c]ount_itself.sh')
实例与自身不匹配,因为带有参数的进程名称包含方括号,但它匹配的模式不包含。
如评论中所述,您应该在变量周围使用双引号以保留空格。
您的结果中似乎有两个相同shell实例的原因是命令替换是在子shell中执行的。有关仅显示父进程的详细信息,请参阅this question。
答案 1 :(得分:2)
进程替换需要父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
由于分叉,您正在看到一个额外的脚本实例。
我不认为可以从输出中可靠地消除那些不需要的进程,因为原则上,脚本可以合法地启动自身的另一个实例(它将作为子进程运行),而你不能区分这两种情况。
一个hacky解决方案是让脚本在调用时在指定位置创建(例如在/tmp/your_script_name
)PID文件,并在终止时将其删除。
答案 2 :(得分:2)
我建议下一步:
排除父亲是我自己的所有流程:
ps --pid $$ -N -a | grep count_itself.sh
这意味着显示父亲不是我自己的所有命令(所以这会排除你的grep进程和你的fork进程来执行反句)
答案 3 :(得分:1)
终于找到了一种方法,尽管是一种丑陋的方式,部分地受到@TomFenech在answer中链接的问题的启发:
#!/bin/bash
nb=$(ps f | grep '[c]ount_itself.sh' | grep -v ' \\_')
echo "$nb"
sleep 20
执行:
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]ount_itself.sh'
将上一个命令限制为仅显示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
grep -v ' \\_'
排除包含4个空格(相当于标签)的行,然后排除\_
对应于子流程的行