如果 shell 脚本中有多个
exec
命令会发生什么,例如:
#!/bin/sh
exec yes > /dev/null &
exec yes alex > /dev/null
我假设仍然需要 fork 才能执行第一个命令,因为 shell 需要继续执行?
或者
&
指定创建一个子进程,然后在其中实际运行exec?
使用
&
意味着子流程。
Background Commands – & If a command is terminated by the control operator ampersand (&), the shell executes the command asynchronously – that is, the shell does not wait for the command to finish before executing the next command.
但是
exec
用于通过命令替换当前进程:
exec [command arg ...] Unless command is omitted, the shell process is replaced with the specified program (which must be a real program, not a shell builtin or function). Any redirections on the exec command are marked as permanent
所以这个功能是互斥的!在语法上:
exec bash -c 'sleep 12' &
这里
exec
没有效果!
演示:
export LANG=C
echo $$
17259
exec sh -c 'echo $$;read foo' &
[1] 17538
17538
[1]+ Stopped exec sh -c 'echo $$;read foo'
fg
exec sh -c 'echo $$;read foo'
17259
我运行脚本:
echo $$;read foo
,以防止在安静地读取之前的输出之前退出。
在此示例中,当前进程 ID 为
17259
。
当使用&符号(
&
)运行时,输出是另一个pid(更大)。当不带 & 符号运行时,新 shell 会替换该命令,并且不会 forked。
将命令替换为:
sh -c 'echo $$;set >/tmp/fork_test-$$.env;read'
重新运行整个测试将在
/tmp
中生成两个文件。
在我的桌子上,我可以读到:
19772
19994
19772
所以我在
/tmp
中找到了两个文件:
-rw-r--r-- 1 user0 user0 2677 jan 22 00:26 /tmp/fork_test-19772.env
-rw-r--r-- 1 user0 user0 2689 jan 22 00:27 /tmp/fork_test-19994.env
如果我跑:
diff /tmp/fork_test-19*env
,我读到:
29c29
< SHLVL='0'
---
> SHLVL='1'
46a47
> _='/bin/sh'
所以第一次运行,带有&符号的是在子级别。
注意: 这是在许多不同的 shell 下进行测试的。
shell fork 来运行后台进程,但这意味着 new shell 仍然需要 fork 来运行
yes
。使用 exec
消除了子 shell 中的分叉。