bash脚本如何将Ctrl-C等效于后台任务?

yon*_*ran 9 bash

有没有办法调用子进程,以便它及其所有后代发送一个中断,就像你Ctrl-C前台任务一样?我正在尝试杀死一个调用一个长期运行的孩子的启动器脚本.我已经尝试过kill -SIGINT $child(它不会向其后代发送中断,因此是无操作)和kill -SIGINT -$child(在交互式调用时有效但在脚本中运行时无效).

这是一个测试脚本.长期运行的脚本是test.sh --child.当你打电话时test.sh --parent,它会调用test.sh --child &然后尝试杀死它.如何让父母成功杀死孩子?

#!/bin/bash

if [ "$1" = "--child" ]; then
sleep 1000

elif [ "$1" = "--parent" ]; then
"$0" --child &
for child in $(jobs -p); do
  echo kill -SIGINT "-$child" && kill -SIGINT "-$child"
done
wait $(jobs -p)

else
echo "Must be invoked with --child or --parent."
fi
Run Code Online (Sandbox Code Playgroud)

我知道你可以修改长时间运行的子trap信号,将它们发送到它的子进程,然后等待(从 Bash脚本杀死Ctrl + C上的背景(大)子),但有没有办法不修改子脚本?

vvo*_*vvo 11

对于任何想知道的人,这是你如何在后台启动孩子并在ctrl + c上杀死他们:

#!/usr/bin/env bash
command1 &
pid[0]=$!
command2 &
pid[1]=$!
trap "kill ${pid[0]} ${pid[1]}; exit 1" INT
wait
Run Code Online (Sandbox Code Playgroud)

  • 这很有用,尽管我发现 `kill` 只会杀死参数中指定的进程,而不是它们的后代。 (2认同)

jim*_*ara 5

somecommand &
Run Code Online (Sandbox Code Playgroud)

返回孩子的pid $!

somecommand &
pid[0]=$!
anothercommand &
pid[1]=$!
trap INT " kill ${pid[0]} ${pid[1]}; exit 1"
wait
Run Code Online (Sandbox Code Playgroud)

我会从这个模型开始,而不是使用bash作业控制(bg,fg,jobs).通常,init继承并获取孤立进程.你想解决什么问题?

  • 难道不是`trap“ kill ....” INT`,而不是`trap INT“ kill ....”`? (2认同)

use*_*001 5

阅读:如何从脚本向脚本发送信号SIGINT?BASH

也来自 info bash

   To facilitate the implementation of the user interface to job  control,
   the operating system maintains the notion of a current terminal process
   group ID.  Members of this process group (processes whose process group
   ID is equal to the current terminal process group ID) receive keyboard-
   generated signals such as SIGINT.  These processes are said  to  be  in
   the  foreground.  Background processes are those whose process group ID
   differs from the terminal's; such processes are immune to keyboard-gen?
   erated signals. 
Run Code Online (Sandbox Code Playgroud)

因此,bash通过进程组ID区分后台进程与前台进程.如果进程组id等于进程id,则该进程是前台进程,并在收到SIGINT信号时终止.否则它将不会终止(除非它被困).

你可以看到进程组ID

ps x -o  "%p %r %y %x %c "
Run Code Online (Sandbox Code Playgroud)

因此,当您&在脚本中运行后台进程(with )时,它将忽略该SIGINT信号,除非它被捕获.

但是,你仍然可以杀死与其他信号,如子进程SIGKILL,SIGTERM等等.

例如,如果将脚本更改为以下内容,则会成功终止子进程:

#!/bin/bash

if [ "$1" = "--child" ]; then
  sleep 1000
elif [ "$1" = "--parent" ]; then
  "$0" --child &
  for child in $(jobs -p); do
    echo kill "$child" && kill "$child"
  done
  wait $(jobs -p)

  else
  echo "Must be invoked with --child or --parent."
fi
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./test.sh --parent
kill 2187
./test.sh: line 10:  2187 Terminated              "$0" --child
Run Code Online (Sandbox Code Playgroud)