默默杀死子shell?

Phi*_*ide 4 kill subshell output

我想实现类似这个Q/A 的东西,但是对于一个子外壳。这是我正在尝试的最小示例:

(subshell=$BASHPID
  (kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)

echo subshell done
Run Code Online (Sandbox Code Playgroud)

我怎样才能让它只subshell done返回而不是:

./test.sh: line 4:  5439 Terminated              ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
Run Code Online (Sandbox Code Playgroud)

编辑:我在这里的术语可能是错误的,通过子外壳我的意思是第一组括号内的过程。

更新:

我想发布来自实际程序的片段以供上下文,上面是一个简化:

# 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
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 7

笔记:

  • wait $subshell不会工作,因为$subshell它不是您正在运行的进程的子进程wait。无论如何,您不会等待进程执行该操作,wait因此这无关紧要。
  • kill $subshell将杀死子外壳,但sleep如果子外壳在运行时设法启动它,则不会kill。但是sleep,您可以在同一进程中运行exec
  • 您可以使用 SIGPIPE 而不是 SIGTERM 来避免该消息
  • 在列表上下文中不加引号的变量在bash.

说了这么多,你可以这样做:

(
  subshell=$BASHPID
  kill -s PIPE "$subshell" &
  sleep 600
)
echo subshell done
Run Code Online (Sandbox Code Playgroud)

(如果您想要杀死而不仅仅是子shell,则替换sleep 60为,在这种情况下,在您杀死它时甚至可能没有时间运行)。exec sleep 60killsleepsleep

无论如何,我不确定你想用它实现什么。

sleep 600 &
Run Code Online (Sandbox Code Playgroud)

sleep如果这是您想要做的(或者(sleep 600 &)如果您想sleep从主 shell隐藏该进程),这将是一种更可靠的在后台启动的方式

现在用你的实际

sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf
Run Code Online (Sandbox Code Playgroud)

命令,请注意它sudo会产生一个子进程来运行命令(如果只是因为它可能需要记录其状态或之后执行一些 PAM 会话任务)。stdbuf然而wpa_supplicant,将在同一个进程中执行,因此最终您将在wpa_supplicant的祖先中拥有三个进程(除了脚本的其余部分):

  1. 子外壳
  2. sudo 作为 1 岁的孩子
  3. wpa_supplicant(之前运行 stdbuf)作为 2 的孩子

如果您杀死 1,则不会自动杀死 2。但是,如果您杀死 2,除非它带有无法拦截的 SIGKILL 信号,否则会杀死 3,因为sudo它将接收到的信号转发给它运行的命令.

无论如何,这不是您想在这里杀死的子shell,它是 3 个或至少 2 个。

现在,如果它正在运行root而脚本的其余部分没有运行,您将无法如此轻松地杀死它。

您需要kill将 完成为root,因此您需要:

sudo WIFI="$wifi" bash -c '
  (echo "$BASHPID" &&
   exec stdbuf -o0 wpa_supplicant -Dwext -i"$WIFI" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1
  ) | {
    read pid &&
      grep -m1 "pre-shared key may be incorrect" &&
      kill -s PIPE "$pid"
  }'
Run Code Online (Sandbox Code Playgroud)

这样,wpa_supplicant将在与$BASHPID子 shell相同的进程中运行,因为我们正在使用exec.

我们通过管道获取 pid 并kill以 root 身份运行。

请注意,如果您准备再等一会儿,

sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 |
  grep -m1 "pre-shared key may be incorrect"
Run Code Online (Sandbox Code Playgroud)

下次它在管道消失后向该管道写入内容,会wpa_supplicant使用 SIGPIPE 自动终止(由系统,因此没有权限问题)。grep

一些 shell 实现不会等待sudoaftergrep返回(让它在后台运行,直到它获得 SIGPIPEd),并且使用bash,您也可以使用grep ... <(sudo ...)语法来做到这一点, wherebash不等待sudo任何一个 aftergrep返回。

更多在Grep 找到匹配后退出缓慢?