两者exec
都env
不要 fork,请参阅以下示例:
docker run --rm -it ubuntu:18.04 sh -c 'exec sleep 1 & ps -Ho pid,ppid,cmd'
PID PPID CMD
1 0 sh -c exec sleep 1 & ps -Ho pid,ppid,cmd
7 1 sleep 1
8 1 ps -Ho pid,ppid,cmd
docker run --rm -it ubuntu:18.04 sh -c 'env sleep 1 & ps -Ho pid,ppid,cmd'
PID PPID CMD
1 0 sh -c env sleep 1 & ps -Ho pid,ppid,cmd
7 1 sleep 1
8 1 ps -Ho pid,ppid,cmd
问题
我看到很多人使用,exec env ...
但我认为没有exec
必要,因为env
它不像exec
.
是否有任何我们需要使用的用例exec env
来代替env
?
答案1
env
(可能)本身不会分叉,只是用它所执行的程序替换自身。但这与父 shell 分叉不同env
,或者只是将其替换为env
。
例如比较这两个:
$ bash -c 'env ls > /dev/null; echo hi'
hi
$ bash -c 'exec env ls > /dev/null; echo hi'
[no output]
使用 时exec
,外壳本身被替换,并且以下内容echo
不会运行。
当然,你有exec env ... &
。使用&
,shell 无论如何都会分叉来启动后台进程,并且它可能不会分叉再次在后台任务中运行单个命令。至少 Bash 优化了这样的情况,例如:
$ bash -c 'ps -Ho pid,ppid,cmd; echo x'
PID PPID CMD
11967 1545 -/bin/bash
14851 11967 bash -c ps -Ho pid,ppid,cmd; echo x
14852 14851 ps -Ho pid,ppid,cmd
x
$ bash -c 'ps -Ho pid,ppid,cmd'
PID PPID CMD
11967 1545 -/bin/bash
14853 11967 ps -Ho pid,ppid,cmd
如果后者不显示中间过程bash
,则行为与存在该过程相同exec
。 (-/bin/bash
是我的交互式 shell。)
Bash 只对单个命令执行此操作,如果有多个命令,shell 会等待最后一个命令退出。使用exec
那里会有所不同:
$ bash -c 'echo x; ps -Ho pid,ppid,cmd'
x
PID PPID CMD
11967 1545 -/bin/bash
14929 11967 bash -c echo x; ps -Ho pid,ppid,cmd
14930 14929 ps -Ho pid,ppid,cmd
$ bash -c 'echo x; exec ps -Ho pid,ppid,cmd'
x
PID PPID CMD
11967 1545 -/bin/bash
14933 11967 ps -Ho pid,ppid,cmd
对于&
,这与以下相同exec ps
:
$ bash -c 'ps -Ho pid,ppid,cmd & sleep 1'
PID PPID CMD
11967 1545 -/bin/bash
14867 11967 bash -c ps -Ho pid,ppid,cmd & sleep 1
14868 14867 ps -Ho pid,ppid,cmd
14869 14867 sleep 1
但通过复合块,我们也可以看到后台 shell 进程:
$ bash -c '{ ps -Ho pid,ppid,cmd; } & sleep 1'
PID PPID CMD
11967 1545 -/bin/bash
14877 11967 bash -c { ps -Ho pid,ppid,cmd; } & sleep 1
14878 14877 bash -c { ps -Ho pid,ppid,cmd; } & sleep 1
14880 14878 ps -Ho pid,ppid,cmd
14879 14877 sleep 1
您没有提供这些人所做的任何具体消息来源exec env
,因此我们不知道他们的确切情况。但是,如果您想用其他进程替换 shell,则可以使用exec env
与 : 相同的方式。exec anyprogram
例如这个模拟示例:
#!/bin/bash
. someconfigfile
if [ "$someconfig" = blah ]; then
exec env myprogram some args...
echo "failed to start" >&2
exit 1
elif
... whatever
fi
那里exec
用启动的程序替换脚本,这样 shell 就不会无用地保留在内存中。此外,如果脚本只有一个启动程序的中介,执行 anexec
将使 PID 保持相同,这使得父级(脚本的父级,然后是程序的)更容易监视其子级。