You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Bash中两种后台执行方式的$!返回PID不同?

两种后台执行脚本命令的差异及$!返回PID不同的原因

一、两个命令的执行逻辑区别

1. 子shell括号语法:(cd /path && ./script.sh) &

括号会触发bash创建一个子shell进程(新的bash实例),这个子shell先执行cd命令,再启动test_link.sh脚本。由于脚本是外部命令,子shell会额外fork一个新进程来运行它——最终test_link.sh是子shell的子进程,$!记录的是后台启动的子shell PID,而非脚本本身的PID。

2. bash -c语法:bash -c "cd /path && ./script.sh" &

bash -c会启动一个新bash进程执行引号内的命令序列。当执行到序列最后一条命令(./test_link.sh)时,bash会调用exec系统调用把自身进程直接替换成脚本进程,不会额外fork新进程。因此最终运行脚本的就是bash -c启动的进程,$!直接返回脚本的PID。

二、$!返回不同PID的核心原因

  • 子shell(括号语法)会保留自身进程,每执行一个外部命令就fork子进程,脚本是子shell的后代进程。
  • bash -c处理命令序列的最后一条外部命令时,会用exec替换自身,避免冗余进程,脚本进程就是bash -c启动的进程本身。

三、解决5小时后杀死脚本的可行方案

方案1:子shell方式下记录脚本PID

执行脚本时直接把它的PID写入临时文件:

(cd /mnt/sda/tcpdump_monitor && ./test_link.sh & echo $! > /tmp/test_link.pid) &

然后给at命令指定杀死这个PID:

echo "kill $(cat /tmp/test_link.pid)" | at +5 hours

方案2:改用bash -c语法

直接用bash -c方式执行,此时$!就是脚本PID,直接使用即可:

bash -c "cd /mnt/sda/tcpdump_monitor && ./test_link.sh" &
echo "kill $!" | at +5 hours

方案3:按进程名杀死(需注意重名风险)

如果脚本名称唯一,可以直接匹配进程名:

echo "pkill -f test_link.sh" | at +5 hours

内容的提问来源于stack exchange,提问作者liang cheng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:37:36