perl – 使用系统时信号传播到父级

前端之家收集整理的这篇文章主要介绍了perl – 使用系统时信号传播到父级前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我编写了一个包装器脚本,使用system()启动另一个脚本.子脚本捕获SIGINT并在内部处理异常.因此,它不应该在退出时将SIGINT传播给它的父级.但是,在某些情况下,父级仍然会收到SIGINT.例如(parent.pl):
  1. use feature qw(say);
  2. use strict;
  3. use warnings;
  4. use POSIX ();
  5.  
  6. my @data = (q(child.pl 'dummy'),q(child.pl),q(bash -c child.pl),q(sh -c child.pl));
  7.  
  8. for ( @data ) {
  9. say "Running command '$_'..";
  10. my $res = system $_;
  11. my $signal = $res & 127;
  12. my $rval = $res >> 8;
  13. say "Parent received return value: $rval";
  14. if ( $signal == POSIX::SIGINT ) {
  15. say "Parent received SIGINT";
  16. }
  17. }

和child.pl:

  1. use feature qw(say);
  2. use strict;
  3. use warnings;
  4.  
  5. eval {
  6. local $SIG{INT} = sub { die "Aborted by user.\n" };
  7. sleep 10;
  8. };
  9. if ( $@ ) {
  10. print "\n" . $@;
  11. exit 0;
  12. }
  13. say "Timed out..";
  14. exit 1;

如果我在超时前按CTRL-C,输出如下:

  1. Running command 'child.pl 'dummy''..
  2. ^C
  3. Aborted by user.
  4. Parent received return value: 0
  5. Parent received SIGINT
  6. Running command 'child.pl'..
  7. ^C
  8. Aborted by user.
  9. Parent received return value: 0
  10. Running command 'bash -c child.pl'..
  11. ^C
  12. Aborted by user.
  13. Parent received return value: 0
  14. Running command 'sh -c child.pl'..
  15. ^C
  16. Aborted by user.
  17. Parent received return value: 0
  18. Parent received SIGINT

因此,在第一种情况和最后一种情况下,父节点接收SIGINT,而对于第二种和第三种情况,它不接收SIGINT.

这是什么原因?如何修复以使SIGINT不会传播给第一个和最后一个案例?

(我怀疑它与Shell的类型有关,即sh vs bash)

解决方法

首先,让我们知道正在执行的内容.
  1. system($shell_command)

是的缩写

  1. system({ "/bin/sh" } "/bin/sh","-c",$shell_command)

除非shell命令不包含shell元字符,但在这种情况下不包含空格

  1. system($shell_command)

是的缩写

  1. my @cmd = split(' ',$shell_command);
  2. system({ $cmd[0] } @cmd)

因此,

  1. system("child.pl 'dummy'") is short for system({ "/bin/sh" } "/bin/sh","child.pl 'dummy'")
  2. system("child.pl") is short for system({ "child.pl" } "child.pl")
  3. system("bash -c child.pl") is short for system({ "bash" } "bash","child.pl")
  4. system("sh -c child.pl") is short for system({ "sh" } "sh","child.pl")

值得注意的是,bash将自己替换为child.pl,而不是在此特定情况下在单独的进程中生成它.这使得child.pl在第三种情况下成为parent.pl的直接子项(就像第二种情况一样).

其次,让我们知道Ctrl-C的作用.

按下Ctrl-C时,终端将SIGINT发送到以该终端为控制终端的每个进程.换句话说,SIGINT被发送到会话的每个进程.

通过添加系统可以看到(“ps -o pid,ppid,pgrp,sid,cmd”);到child.pl,我们的会话中有三到四个进程,具体取决于测试用例.

> child.pl:child.pl处理SIGINT.它没有被它杀死.
> shell在测试用例1和4中由parent.pl启动:shell被SIGINT杀死.
> parent.pl:系统相当于本地$SIG {INT} =’IGNORE’;,因此忽略了SIGINT.
>启动parent.pl的登录shell:它忽略了SIGINT,但我不知道为什么.我猜它是因为它是一个交互式shell.

所以,这就是你所观察到的:

>当parent.pl的(直接)子节点是child.pl [测试用例2和3]时,子节点(child.pl)不会死于SIGINT,因为它处理SIGINT.>当parent.pl的(直接)子节点是shell [测试用例1和4]时,子节点(shell)从SIGINT消失,因为非交互式shell不处理/忽略SIGINT.

猜你在找的Perl相关文章