bash:4.3.42(1)-发行版(x86_64-pc-linux-gnu)
执行以下脚本:
# This is myscript.sh
line=$(ps aux | grep [m]yscript) # A => returns two duplicates processes (why?)
echo"'$line'"
ps aux | grep [m]yscript # B => returns only one
输出:
'tom 31836 0.0 0.0 17656 3132 pts/25 S+ 10:33 0:00 bash myscript.sh
tom 31837 0.0 0.0 17660 1736 pts/25 S+ 10:33 0:00 bash myscript.sh'
tom 31836 0.0 0.0 17660 3428 pts/25 S+ 10:33 0:00 bash myscript.sh
为什么内联执行的ps -snippet(A)返回两行?
看来您正在运行两个脚本:`ps -ef | grep -E" 31837 | 31836"
命令替换($(...))
管道的每个部分[1]
导致Bash创建一个子Shell(通过分叉当前Shell进程创建的子进程),但是如果Bash导致一次调用外部实用程序,则Bash会优化掉子Shell。
(我认为在优化方案中发生的事情是实际上创建了一个子外壳,但是随后通过exec之类的东西立即被外部实用程序的进程所取代。如果您确定知道,请告诉我。)
应用于您的示例:
line=$(ps aux | grep [m]yscript)创建3个子进程:
1个子shell-您看到的脚本的分支,是grep返回的附加匹配项。
2个子进程(每个管道段1个)-ps和grep;它们代替了优化后的子外壳;它们的父进程是命令替换创建的剩余的1个子shell。
ps aux | grep [m]yscript创建2个子进程(每个管道段1个):
ps和grep;它们代替了优化后的子外壳;他们的父进程是当前的shell。
有关在Bash中创建子Shell的方案的概述,请参阅我的答案,但是,本文不涵盖优化方案。
[1]在Bash v4.2 +中,您可以设置选项lastpipe(默认情况下处于关闭状态),以使最后一个管道段在当前shell中而不是子shell中运行;除了稍微提高效率外,这还允许您在管道退出后当前shell可以看到的最后一段中声明变量。
我把支票交给另一个答案,因为它更快。 但是这个答案也很好。 谢谢
感谢您的反馈和支持,tokosh。 (我在@ John1024s之后写了这个答案,因为,尽管他的答案是有用和正确的,但我仍然觉得它缺少可在相关场景中提供帮助的背景信息-您绝对可以使用管道段创建的(非临时性)子shell结束 )
好的,我不得不承认"因为更快"是一个愚蠢的论点。 但是,我还是照原样保留了(你们两个都应该得到)。 因此,对于链接的答案,+ 1(不能做更多的事情)。
摘要
这将创建一个子外壳,因此两个进程正在运行:
line=$(ps aux | grep [m]yscript)
这不会创建子外壳。因此,myscript.sh仅运行一个进程:
ps aux | grep [m]yscript
示范
让我们稍微修改一下脚本,以便将流程和子流程的PID保存在变量line中:
$ cat myscript.sh
# This is myscript.sh
line=$(ps aux | grep [m]yscript; echo $$ $BASHPID)
echo"'$line'"
ps aux | grep [m]yscript
在bash脚本中,$$是脚本的PID,在子shell中未更改。相反,当输入子外壳程序时,bash使用子外壳程序的PID更新$BASHPID。
这是输出:
$ bash myscript.sh
'john1024 30226 0.0 0.0 13280 2884 pts/22 S+ 18:50 0:00 bash myscript.sh
john1024 30227 0.0 0.0 13284 1824 pts/22 S+ 18:50 0:00 bash myscript.sh
30226 30227'
john1024 30226 0.0 0.0 13284 3196 pts/22 S+ 18:50 0:00 bash myscript.sh
在这种情况下,30226是主脚本上的PID,而30227是运行ps aux | grep [m]yscript的子外壳的PID。