在交互式控制台中,按^C
关闭zenity --info & fg
Zenity 窗口。只能zenity --info & wait
在脚本中使用。但^C
在这种情况下不会关闭 Zenity 窗口。有没有什么办法可以让wait
行为变得更像fg
工作^C
?
答案1
您可以做的最简单的事情就是捕获SIGINT
(^C) 并从处理程序中终止后台进程:
#! /bin/sh
trap 'kill "$!"; exit 1' INT QUIT
zenity --info &
wait
当从某些 shell 调用脚本时,例如bash
实现所谓的《等待并配合退出》(看这里供讨论),程序在收到信号后干净退出的预期方法是重置处理程序,然后用相同的信号杀死自身:
#! /bin/sh
termsig(){ trap - "$1"; kill "$!"; kill -s "$1" "$$"; }
trap 'termsig INT' INT
trap 'termsig QUIT' QUIT
zenity --info &
wait
当然,所有这些都是相当粗俗的,并且无法对zenity
本身可能产生的子进程做任何事情,并且必须针对多个后台进程进行调整。更明显的解决方案(trap - INT; zenity --info) &
将不是/bin/sh
与任何 Debian 衍生发行版(Ubuntu 等)或任何基于 busybox 的系统一起使用。
另一个解决方案是通过包装器运行您的程序,该包装器允许您将SIGINT
配置重置为默认值,例如。和perl
:
#! /bin/sh
perl -e '$SIG{INT} = $SIG{QUIT} = "DEFAULT"; exec @ARGV' zenity --info &
wait
perl
但如果你这样做,你也可以用or重写整个脚本python
;-)
答案2
在非交互式中sh
,命令异步运行,并&
忽略其 SIGINT 和 SIGQUIT 信号。
tcsetpgrp()
这是 POSIX 的要求,可以追溯到终端作业控制 ( ...) 不存在的时代。如今,它通常会成为障碍。
另一个来自同一来源的 POSIX 要求是,当 shell 启动时忽略信号时,不能使用 来取消忽略该信号trap
。再说一遍,如今,这是不受欢迎且令人讨厌的行为。
zsh
仅部分实现了后一个要求。恢复trap - SIGNAL
默认配置的忽略SIGNAL
被忽略,但trap handler SIGNAL
安装handler
for SIGNAL 即使该信号在启动时被忽略,因此如果他们确实想要使用 .a 仍然可以恢复默认配置trap : SIGNAL; trap - SIGNAL
。
只要脚本中不忽略 SIGINT(例如当脚本在后台运行时),您就可以执行以下操作:
#! /bin/sh -
(trap - INT QUIT; exec zenity) & wait
恢复 SIGINT 和 SIGQUIT 的默认配置。
然而,尽管 POSIX 明确表示它应该可以工作,它不需要一些sh
实现。特别是,不适用于dash
和大多数其他ash
导数,ksh93
,bosh
或yash
。因此,您可能需要将 she-bang 更改为#! /bin/bash -
or #! /bin/zsh -
or#! /bin/mksh -
以确保在本例中您有一个符合 POSIX 标准的 shell。
如果 SIGINT 在 shell 启动时被忽略,您需要使用以下命令zsh
来恢复它们的配置:
#! /bin/zsh -
trap : INT QUIT # noop handler to unignore
trap - INT QUIT # restore default disposition for the shell
(trap - INT QUIT; zenity) & wait
示例(此处在 Linux 上,信号配置在 中以位图形式公开/proc/<pid>/status
):
$ sh -c 'grep SigIgn /proc/self/status'
SigIgn: 0000000000000000
$ sh -c 'grep SigIgn /proc/self/status & wait'
SigIgn: 0000000000000006 # (1<<(SIGINT-1) | 1<<(SIGQUIT-1))
$ zsh -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000000
$ bash -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000000
$ mksh -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000000
$ dash -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000006
$ ksh93 -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000006
$ yash -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000000006
$ bosh -c '(trap - INT QUIT; exec grep SigIgn /proc/self/status) & wait'
SigIgn: 0000000000100006 # also SIGTTIN
$ (bash -c 'grep SigIgn /proc/self/status' & wait)
SigIgn: 0000000000000006
$ (bash -c 'trap - INT QUIT; grep SigIgn /proc/self/status' & wait)
SigIgn: 0000000000000006
$ (zsh -c 'grep SigIgn /proc/self/status' & wait)
SigIgn: 0000000000000002 # not sure why the SIGQUIT was unignored
$ (zsh -c 'trap - INT QUIT; grep SigIgn /proc/self/status' & wait)
SigIgn: 0000000000000002
$ (zsh -c 'trap : INT QUIT; trap - INT QUIT; grep SigIgn /proc/self/status' & wait)
SigIgn: 0000000000000000