背景
我读过一篇邮政关于信号的处理SIGINT
,但我仍然不明白如何在代码中正确处理它,这些代码将由交互式和非交互式 shell 获取和使用。
我将给出我的脚本的简化示例,并针对特定部分提出问题。
例子
我有一个具有有用功能的脚本,可以在任何地方获取和使用。
/tmp/useful_functions.sh
#!/bin/bash
function example()
{
echo "Main script started"
# Make process run forever in the background.
( while sleep 1; do echo "Background script running"; done ) &
# Make subshell work for 10 seconds.
local output="$(sleep 10; echo "Subshell completed")"
echo "${output}"
# Kill the backgrounded process once the subshell has finished.
{ kill "${!}" && wait "${!}"; } &> /dev/null
echo "Main script completed"
}
测试1
让我们使用例子在另一个脚本中运行。
/tmp/test.sh
#!/bin/bash
source /tmp/useful_functions.sh
example
现在让我们在 subshell 工作时运行/tmp/test.sh
并按下。 (子外壳 = )Control-C
$(sleep 10; echo "Subshell completed")
由于。。。导致的结果Test 1
/tmp/test.sh
、example
、subshell
进程background
已终止。
提示正在等待新输入。
问题
SIGINT
进程之间发送/处理/传播的顺序是什么?
(提到SIGINT
应发送至所有前景进程,并且最内部的进程应该首先处理它。)- 为什么后台进程被终止?
测试2
让我们使用例子直接在交互式 Bash 中运行:
...$ source /tmp/useful_functions.sh
...$ example
Control-C
当 subshell 工作时再次按下。
(子外壳 = $(sleep 10; echo "Subshell completed")
)
由于。。。导致的结果Test 2
example
进程subshell
已终止,但backgrounded
进程仍保持活动状态。即使打印了进程
的输出,提示仍在等待新的输入。backgrounded
问题
SIGINT
进程之间发送/处理/传播的顺序是什么?- 为什么后台进程现在没有终止?
改进示例
尽管我不完全理解 的行为Test 1
,但这种行为是我所期望的,我也想通过交互式 Bash 来实现这一目标。
想法是创建另一个子 shell,它包装后台进程和现有子 shell,并希望新进程的终止将导致后台进程和现有子 shell 的终止。
/tmp/useful_functions.sh
#!/bin/bash
function example()
{
(
echo "Main script started"
# Make process run forever in the background.
( while sleep 1; do echo "Background script running"; done ) &
# Make subshell work for 10 seconds.
local output="$(sleep 10; echo "Subshell completed")"
echo "${output}"
# Kill the backgrounded process once the subshell has finished.
{ kill "${!}" && wait "${!}"; } &> /dev/null
echo "Main script completed"
)
}
重复的结果Test 1
/tmp/test.sh
、example
、outer subshell
和inner subshell
进程background
已终止。
提示正在等待新输入。
问题
SIGINT
进程之间发送/处理/传播的顺序是什么?- 为什么后台进程被终止?
重复的结果Test 2
example
、outer subshell
、inner subshell
进程background
已终止。
提示正在等待新输入。
问题
SIGINT
进程之间发送/处理/传播的顺序是什么?- 为什么后台进程被终止?
问题
此时我意识到我实际上必须在后台进程之后进行一些清理,并且我需要捕获SIGINT
某个地方来处理它。
解决方案
因为我不知道SIGINT
Bash 中一般是如何处理和传播的,所以我做了一些有根据的猜测,并提出了我认为可以正常工作的解决方案,但不能确定。
#!/bin/bash
function example()
{
(
echo "Main script started"
# Make process run forever in the background.
(
trap "echo Cleanup; trap - SIGINT; kill -s SIGINT ${$}" SIGINT
while sleep 1; do echo "Background script running"; done
) &
# Make subshell work for 10 seconds.
local output="$(sleep 10; echo "Subshell completed")"
echo "${output}"
# Kill the backgrounded process once the subshell has finished.
{ kill "${!}" && wait "${!}"; } &> /dev/null
echo "Main script completed"
)
}
问题
- 我的陷阱能正确处理/传播
SIGINT
吗? - 是
${$}
正确的流程吗?
(在提到的帖子中,据说该进程应该杀死自己,但他们的示例使用${$}
而不是${BASHPID}
。)