接上文,再来看一下exec
这个bash shell
内置命令:
exec [-cl] [-a name] [command [arguments]]
If command is specified, it replaces the shell. No new process is created. The arguments become the arguments to command. If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is what login(1) does. The -c option causes command to be executed with an empty environment. If -a is supplied, the shell passes name as the zeroth argument to the executed command. If command cannot be executed for some reason, a non-interactive shell exits, unless the shell option execfail is enabled, in which case it returns failure. An interactive shell returns failure if the file cannot be executed. If command is not specified, any redirections take effect in the current shell, and the return status is 0. If there is a redirection error, the return status is 1.
可以看到,当用exec
执行一个命令时,不会产生新的进程,并且这个命令会替换掉当前的bash shell
进程。让我们看个例子。在一个终端执行下列命令:
[root@localhost ~]# echo $$
22330
[root@localhost ~]# exec sleep 60
再在另一个终端执行下列命令:
[root@localhost ~]# ps -ef | grep 22330
root 22330 22329 0 05:50 pts/0 00:00:00 sleep 60
root 22361 22345 0 05:52 pts/1 00:00:00 grep --color=auto 22330
可以看到22330
号进程变成了sleep 60
,而不是bash shell
进程了。60
秒后,sleep 60
进程结束了,终端也退出了:
[root@localhost ~]# ps -ef | grep 22330
root 22363 22345 0 05:56 pts/1 00:00:00 grep --color=auto 22330
最后,通过演示经典的《Shell十三问》
中《exec跟source差在哪?》
一章结尾的例子,再好好理解一下bash shell
进程的相关问题:
1.sh
:
#!/bin/bash
A=B
echo "PID for 1.sh before exec/source/fork:$$"
export A
echo "1.sh: \$A is $A"
case $1 in
exec)
echo "using exec..."
exec ./2.sh ;;
source)
echo "using source..."
. ./2.sh ;;
*)
echo "using fork by default..."
./2.sh ;;
esac
echo "PID for 1.sh after exec/source/fork:$$"
echo "1.sh: \$A is $A"
2.sh
:
#!/bin/bash
echo "PID for 2.sh: $$"
echo "2.sh get \$A=$A from 1.sh"
A=C
export A
echo "2.sh: \$A is $A"
(1)执行“./1.sh fork
”:
[root@localhost ~]# ./1.sh fork
PID for 1.sh before exec/source/fork:22390
1.sh: $A is B
using fork by default...
PID for 2.sh: 22391
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:22390
1.sh: $A is B
可以看到,由于1.sh
脚本(进程ID
为22390
)会新起一个subshell
进程去执行2.sh
(进程ID
为22391
),所以在2.sh
脚本中对A
的修改不会影响到1.sh
脚本中A
的值。
(2)执行“./1.sh source
”:
[root@localhost ~]# ./1.sh source
PID for 1.sh before exec/source/fork:22393
1.sh: $A is B
using source...
PID for 2.sh: 22393
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:22393
1.sh: $A is C
可以看到,由于2.sh
脚本会在1.sh
脚本进程中运行(打印出的进程ID
均为22393
),所以在2.sh
脚本中对A
的修改会影响到1.sh
脚本中A
的值。
(3)执行“./1.sh exec
”:
[root@localhost ~]# ./1.sh exec
PID for 1.sh before exec/source/fork:22396
1.sh: $A is B
using exec...
PID for 2.sh: 22396
2.sh get $A=B from 1.sh
2.sh: $A is C
2.sh
脚本会在1.sh
脚本进程中运行(打印出的进程ID
均为22396
),同时原有的1.sh
脚本进程不会再运行。所以2.sh
脚本运行结束后,不会再执行1.sh
脚本的命令。
参考资料:
Shell十三问