bash 中 $(cmd1|cmd2)会在当前进程下创建子进程?

问题发现

这几天写shell脚本时,发现$(cmd1|cmd2)会创建子进程

脚本如下:

#!/bin/bash
echo -e '\n\033[32;1m-----------\033[0m'                              
echo "The name of this file is $(basename $0)."                       
echo "The pid of this program is $$."                                 

echo -e '\n\033[32;1m---- 0 ----\033[0m'                              
echo -e '\033[33;1mCMD: ps -ef|grep "aaaa.sh"|grep -v grep\033[0m'    
ps -ef|grep "aaaa.sh"|grep -v grep 

echo -e '\n\033[32;1m---- 1 ----\033[0m'                              
echo -e '\033[33;1mCMD: ps -ef|grep "aaaa.sh"|grep -v "bbbb"|grep -v grep\033[0m'                                                            
ps -ef|grep "aaaa.sh"|grep -v "bbbb"|grep -v grep                     

echo -e '\n\033[32;1m---- 2 ----\033[0m'                              
echo -e '\033[33;1mCMD: pgrep -a "aaaa.sh"|grep -v "bbbb"\033[0m'     
pgrep -a "aaaa.sh"|grep -v "bbbb"  

echo -e '\n\033[32;1m---- 3 ----\033[0m'                              
echo -e '\033[33;1mCMD: pgrep -a "aaaa.sh"|grep -v "$$"\033[0m'       
pgrep -a "aaaa.sh"|grep -v "$$"    

echo -e '\n\033[32;1m---- 4 ----\033[0m'                              
echo -e '\033[33;1mCMD: output=$(ps -ef|grep "aaaa.sh"|grep -v "bbbb"|grep -v grep)\033[0m'                                                  
output=$(ps -ef|grep "aaaa.sh"|grep -v "bbbb"|grep -v grep)           
echo -e "$output"                  

echo -e '\n\033[32;1m---- 5 ----\033[0m'                              
echo -e '\033[33;1mCMD: output=$(ps -ef|grep "aaaa.sh"|grep -v "$$"|grep -v grep)\033[0m'                                                    
output=$(ps -ef|grep "aaaa.sh"|grep -v "$$"|grep -v grep)             
echo -e "$output"                  

echo -e '\n\033[32;1m---- 6 ----\033[0m'                              
echo -e '\033[33;1mCMD: output=$(pgrep -a "aaaa.sh"|grep -v "bbbb")\033[0m'                                                                  
output=$(pgrep -a "aaaa.sh"|grep -v "bbbb")                           
echo -e "$output"                  

echo -e '\n\033[32;1m---- 7 ----\033[0m'                              
echo -e '\033[33;1mCMD: output=$(pgrep -a "aaaa.sh"|grep -v "$$")\033[0m'                                                                    
output=$(pgrep -a "aaaa.sh"|grep -v "$$")                             
echo -e "$output"                  

echo -e '\n\033[32;1m---- 8 ----\033[0m'                              
echo -e '\033[33;1mCMD: output=$(pgrep -a "aaaa.sh")\033[0m'          
output=$(pgrep -a "aaaa.sh")       
echo -e "$output"                  

echo -e '\n\033[32;1m-----------\033[0m'

输出结果

aaaa.sh 输出

疑问

其中的 4、5、6、7项都输出了两个进程,请问这是shell自身的机制吗?

阅读 4k
1 个回答

得理解bash解释执行脚本的机制,当执行./aaaa.sh的初始,就已经fork()了一个子进程,这个子进程的父进程是当前登录shell
随着脚本内容的被执行,根据每行命令的不同,又有不同的执行方式:
echo命令属于bash内置命令,它在执行时相当于执行bash内部的一个函数,不创建子进程。
grepps等属于外部命令(不是bash本身内部实现的命令),它们在执行时需要经过fork()execve(),都需要创建子进程。
而bash对管道|又有特殊处理,处于管道两侧的命令,会分别运行于两个子shell(每个子shell都属于原父shell的子进程),不过前一个命令的标准输出会连接到后一个命令的标准输入。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进