1

目前观察到我描述的行为发生在 OS X 上。

Bash 脚本parent-script.sh包含一个命令eval $SCRIPT,其中SCRIPT是一个字符串,例如./another-script.sh.

如果another-script.sh是一个长时间运行的脚本,我parent-script在它运行时发送一个信号,似乎发生的事情(我检查使用pstree是子shell执行another-script没有终止,它变成了.launchd

它的 STDOUT 仍然绑定到启动parent-script.

如何修改此行为?此外,真正导致这种行为的原因是什么?(这样我就可以了解什么时候会出现这种行为)

Linux 标签在这里是因为我想知道如果 Linux 的行为有所不同,它在这里的表现如何。

我也开始意识到我可能正在触及一个非常深奥的话题的表面。因此,欢迎提供优质阅读材料的链接!

4

2 回答 2

4

这是正常的,也是意料之中的。

你发送了一个信号(大概是SIGTERMparent-script,它死了,但没有信号被发送到another-script. 它继续运行。

这与parent-script作业在终端上以交互方式运行并且您键入^C(或^Z)时发生的情况不同。在这种情况下,一个SIGINT信号会自动发送到整个前台进程组。由于another-script与(默认情况下)不是同一进程组parent-script,因此它们都收到信号并且都死了。

如果您想another-script在其父项在任何其他上下文中死亡时自动死亡,而不是当它是在具有作业控制的终端中运行的作业时,您有几个选择。

  • parent-script可以捕获SIGTERM信号。在信号处理程序中,它杀死它的孩子,然后退出自己。当然,这是不可靠的:如果parent-script崩溃或被无法捕获的信号杀死,则不会进行清理。但它通常被认为足够好。
  • 通常,another-script当其父级退出时自然会退出,您无需做任何特别的事情。如果两个进程通过管道交换数据,这通常是正确的:子进程将获得 EOF(如果读取)或SIGPIPEEPIPE(如果写入),因此会注意到其父进程已消失并自行退出。
  • 否则,another-script可以采取显式步骤定期检查其父级是否已消失,如果发现它已成为init/的子级,则自动退出launchd。同样,您可以为此使用管道或其他 IPC 机制,但最简单的可能是它检查自己的父进程 ID。
于 2013-07-07T03:28:00.803 回答
1

我尝试使用以下脚本来模拟您观察到的内容(在 Mac OS X 10.8.4 上):

父脚本.sh

SCRIPT=./another-script.sh
trap "echo Exiting; exit 1" 0 1 2 3 13 15
eval $SCRIPT
trap 0
echo "Normal exit"

另一个脚本.sh

for i in $(seq 1 100)
do echo "Sequence $i"; sleep 2; done

当我运行它时,我得到了,例如:

$  ./parent-script.sh
Sequence 1
Sequence 2
Sequence 3
Sequence 4
^CExiting
Exiting
$

当我another-script.sh这样修改时:

trap '' 1 2 3 13 15
for i in $(seq 1 100)
do echo "Sequence $i"; sleep 2; done

我得到了(异常?)行为:

$ ./parent-script.sh
Sequence 1
Sequence 2
Sequence 3
Sequence 4
^CSequence 5
Sequence 6
^CSequence 7
^CSequence 8
Sequence 9
^CSequence 10
^CSequence 11
^\Sequence 12
Sequence 13
Sequence 14
Sequence 15
Sequence 16
Sequence 17
Sequence 18
Sequence 19
Sequence 20
./parent-script.sh: line 3: 71135 Abort trap: 6           ./another-script.sh
Exiting
Exiting
$

我不得不创建另一个终端窗口并发送kill -6 71135以停止父进程,我认为这是完全错误的。我向父进程发送了中断;当我这样做时,它应该立即退出(通过陷阱)。它应该让子进程运行;它使自己免受中断。我以前对这种行为感到愤怒。eval不需要得到效果;没有它执行脚本就足够了。

但是,ksh也表现出相同的方式。因此,要么 Apple 一直小心地将相同的错误引入到两个 shell 中,要么就是某人(POSIX?)规定 shell 应该表现的方式。

于 2013-07-07T03:35:07.217 回答