我试图以这样的方式处理SIGINT / CTRL + C中断:如果用户意外按下ctrl-c,系统会提示他“你想退出吗?(是/否)”。如果他输入yes,则退出脚本。如果否,则从中断发生的地方继续。基本上,我需要Ctrl-C工作类似于Ctrl-Z / SINTSTP,但方式略有不同。我尝试了各种方法来解决这个问题,但我没有得到预期的结果。以下是我尝试过的几个场景。
案例:1
脚本:play.sh
create table t ( id varchar2(20), val number );
delete from t;
INSERT INTO t ( id, val ) values ( '12345', 50);
INSERT INTO t ( id, val ) values ( '12345', 50);
INSERT INTO t ( id, val ) values ( '12345', -50);
INSERT INTO t ( id, val ) values ( '12345', -50);
INSERT INTO t ( id, val ) values ( 'abcde', 40);
INSERT INTO t ( id, val ) values ( 'abcde', 40);
INSERT INTO t ( id, val ) values ( 'abcde', 20);
INSERT INTO t ( id, val ) values ( 'abcde', 40);
INSERT INTO t ( id, val ) values ( 'abcde', -40);
INSERT INTO t ( id, val ) values ( '11111', 30);
INSERT INTO t ( id, val ) values ( '11111', -30);
INSERT INTO t ( id, val ) values ( '11111', -30);
INSERT INTO t ( id, val ) values ( 'aaaaa', 10);
INSERT INTO t ( id, val ) values ( 'aaaaa', -30);
COMMIT;
MERGE INTO t
USING (WITH value_partition AS
(SELECT t.*,
ROW_NUMBER () OVER (PARTITION BY t.id, t.val ORDER BY ROWID) rn_in_value
FROM t)
SELECT sp.ROWID row_id,
sp.*,
CASE WHEN SUM (sp.val) OVER (PARTITION BY sp.id, ABS (sp.val), rn_in_value) = 0 THEN 'N' ELSE 'Y' END
keep_row
FROM value_partition sp) u
ON (t.ROWID = u.row_id
AND u.keep_row = 'N')
WHEN MATCHED THEN
UPDATE SET t.val = u.val
DELETE
WHERE u.keep_row = 'N';
SELECT * FROM t;
当我运行上面的脚本时,我得到了预期的结果。
输出:
#!/bin/sh
function stop()
{
while true; do
read -rep $'\nDo you wish to stop playing?(y/n)' yn
case $yn in
[Yy]* ) echo "Thanks for playing !!!"; exit 1;;
[Nn]* ) break;;
* ) echo "Please answer (y/n)";;
esac
done
}
trap 'stop' SIGINT
echo "going to sleep"
for i in {1..100}
do
echo "$i"
sleep 3
done
echo "end of sleep"
案例:2 我将for循环移动到新的脚本 loop.sh ,因此play.sh成为父进程,loop.sh成为子进程。
脚本:play.sh
$ play.sh
going to sleep
1
^C
Do you wish to stop playing?(y/n)y
Thanks for playing !!!
$ play.sh
going to sleep
1
2
^C
Do you wish to stop playing?(y/n)n
3
4
^C
Do you wish to stop playing?(y/n)y
Thanks for playing !!!
$
脚本:loop.sh
#!/bin/sh
function stop()
{
while true; do
read -rep $'\nDo you wish to stop playing?(y/n)' yn
case $yn in
[Yy]* ) echo "Thanks for playing !!!"; exit 1;;
[Nn]* ) break;;
* ) echo "Please answer (y/n)";;
esac
done
}
trap 'stop' SIGINT
loop.sh
此情况下的输出与预期不符。
输出:
#!/bin/sh
echo "going to sleep"
for i in {1..100}
do
echo "$i"
sleep 3
done
echo "end of sleep"
我理解当进程收到SIGINT信号时,它会将信号传播到所有子进程,因此我的第二种情况失败了。有没有办法可以避免SIGINT传播到子进程,从而使 loop.sh 完全按照它在第一种情况下的工作方式工作?
注意: 这只是我实际应用的一个示例。 我正在处理的应用程序在play.sh和loop.sh中有几个子脚本。我应该确保接收SIGINT的应用程序不应该终止,但它应该提示用户输入消息。
答案 0 :(得分:1)
在play.sh
中不要调用新脚本,但请将其源于此:
source ./loop.sh
我说由于没有为脚本生成新的子shell,当你退出陷阱时程序流程会继续。如果您调用新脚本,则陷阱将传播到子shell,但如果退出子shell,它将无法返回。