我想实现类似Q/A 的东西,但要使用子外壳。这是我正在尝试的一个最小示例:
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)
echo subshell done
我怎样才能使它只subshell done
返回而不是:
./test.sh: line 4: 5439 Terminated ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
编辑:我在这里的术语可能是错误的,子shell是指第一组括号内的过程。
更新:
我想从实际程序中发布片段以获取上下文,上面是一个简化:
# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then
# code to setup wpa configurations here
# If wifi key is wrong kill subshell
subshell=$BASHPID
(sudo stdbuf -o0 wpa_supplicant -Dwext -i$wifi -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 \
| grep -m 1 "pre-shared key may be incorrect" \
&& kill -s PIPE "$subshell") &
# More code which does the setup necessary for wifi
) && connected=true
# later json will be returned based on if connected is set
笔记:
wait $subshell
不会工作,因为$subshell
它不是你正在运行的进程的子进程wait
。无论如何,你不会等待进程这样做,wait
所以这并不重要。kill $subshell
将杀死子shell,但sleep
如果子shell 在运行时已成功启动它,则不会kill
。但是,您可以sleep
在同一进程中运行exec
bash
.说了这么多,你可以这样做:
(如果您想杀死而不仅仅是子shell,请替换
sleep 60
为,在这种情况下,您杀死它时甚至可能没有时间运行)。exec sleep 60
kill
sleep
sleep
无论如何,我不确定你想用它来实现什么。
sleep
如果这是您想要做的(或者(sleep 600 &)
如果您想sleep
从主 shell 隐藏该进程),这将是一种更可靠的在后台启动的方式现在用你的实际
命令,请注意,它
sudo
确实会产生一个子进程来运行该命令(如果只是因为它可能需要记录其状态或之后执行一些 PAM 会话任务)。stdbuf
然而,将在同一个进程中执行,所以最后你将在的祖先wpa_supplicant
中拥有三个进程(除了脚本的其余部分) :wpa_supplicant
如果您杀死 1,则不会自动杀死 2。但是,如果您杀死 2,除非它带有无法拦截的 SIGKILL 之类的信号,否则它将杀死 3,因为
sudo
它会将收到的信号转发给它运行的命令.无论如何,这不是您要在这里杀死的子shell,它是 3 或至少 2。
现在,如果它正在运行
root
而脚本的其余部分没有运行,您将无法如此轻松地杀死它。你需要
kill
做 asroot
,所以你需要:这样,
wpa_supplicant
将在与$BASHPID
子shell 相同的进程中运行,就像我们使用exec
.我们通过管道获取 pid 并
kill
以 root 身份运行。请注意,如果您准备再等一会儿,
下次它在消失后向该管道写入内容时会
wpa_supplicant
使用 SIGPIPE 自动终止(由系统执行,因此没有权限问题) 。grep
某些 shell 实现不会等待
sudo
aftergrep
返回(让它在后台运行,直到它获得 SIGPIPEd),并且使用bash
,您也可以使用grep ... <(sudo ...)
语法来执行此操作,其中bash
不等待sudo
之后grep
返回。找到匹配项后,Grep 的更多信息退出缓慢?
子shell 是指一个shell 命令,它是某个shell 的子级,例如为
bash -i
您提供$
提示的交互式登录shell 的子级。您不必在子 shell 中运行命令 - 您可以选择将其作为独立进程运行。听起来这可能是合适的,因为您不希望它的 stdout / stderr 弄乱进度条的外观,并且因为您不希望父 shell 报告甚至注意到其子进程的死亡。有一些标准工具可以实现这一点,例如daemonize和 nohup。(另请参见手册 页。)使用nohup可能是最好的选择。这是一个使用它来运行一个不创建 nohup.out 的简单程序的示例:
让您的程序或程序的包装脚本在 /tmp/my.pid 中记录其 PID —— bash 将其作为
$$
变量提供。那么带有进度条的监控过程就可以了当它不再需要该程序进行任何处理时。或者,您可能更愿意将您的程序名称提供给
killall
.你可能正在寻找这个
这里子shell被置于后台,然后父shell等待但等待输出发送到/dev/null。这会捕获
Terminated
消息。请注意,如果您更改等待以将输出捕获到文件,例如
wait $! 2>wait_output
,您将看到表明这
Terminated
是来自父外壳。如果在杀死之前有一些活动,请进行一个小检查以查看它是否有效
此示例将在打印前暂停一秒钟
subshell done
。此示例还显示了如何在同一行进行后台处理和等待,例如& wait 2>wait_output
. 我不确定这是否比带有wait $!
.这里要注意的关键是
Terminated
消息来自顶级父 shell 作业控制。这就是看到子外壳终止并生成消息的原因。所以这就是你想要捕捉输出的地方。重定向wait
命令输出会执行此操作。