Perl $SIG{INT}=&x27;忽略';不使用Net::OpenSSH
我需要在后台通过$ssh->system执行命令,并且有文档记录,这应该像本地“system”命令一样: 实际上,这似乎不是真的,因为当收到SIGINT时,子系统中的$ssh->system会立即终止,即使我明确希望先“忽略”它:Perl $SIG{INT}=&x27;忽略';不使用Net::OpenSSH,perl,perl-module,openssh,Perl,Perl Module,Openssh,我需要在后台通过$ssh->system执行命令,并且有文档记录,这应该像本地“system”命令一样: 实际上,这似乎不是真的,因为当收到SIGINT时,子系统中的$ssh->system会立即终止,即使我明确希望先“忽略”它: use warnings; use strict; use POSIX ":sys_wait_h"; use Net::OpenSSH; my $CTRLC=0; $SIG{CHLD}='IGNORE'; sub _int_handler { $CTRLC++
use warnings;
use strict;
use POSIX ":sys_wait_h";
use Net::OpenSSH;
my $CTRLC=0;
$SIG{CHLD}='IGNORE';
sub _int_handler {
$CTRLC++;
print "CTRL-C was pressed $CTRLC times!!!\n";
}
$SIG{INT}='IGNORE';
my $SSH=Net::OpenSSH->new('testhost',
forward_agent => 1,
master_stderr_discard => 1,
master_opts => [ -o =>"PasswordAuthentication=no"]);
$SIG{INT}=\&_int_handler;
sub _ssh {
$SIG{INT}='IGNORE';
$SSH->system('sleep 3; sleep 3');
# system('sleep 3; sleep 3');
print "Exiting Child!\n";
exit 0;
}
print "Starting shell ...\n";
_ssh if not (my $PID=fork);
print $PID, "\n";
waitpid ($PID,0);
当运行此代码并试图在第一个“sleep3”启动后中断时,“$SSH->system”调用立即结束
但是,如果您使用下面的本地“system”语句,则可以正确捕获SIGINT
在Net::OpenSSH的源代码中,我发现$SIG{INT}在“system”子目录中也显式地设置为“IGNORE”。我不知道这为什么不起作用
我会感谢任何可能的解决方案,如果它意味着以不同的方式做事的话。最后,我只想远程执行命令,并且仍然保护它们不受CTRL-C的影响
谢谢,
玛兹
更新:
感谢您在salva上的投入。我进一步简化了内容,最后它似乎是ssh的“-S”标志:
$SIG{INT}='IGNORE';
# system('ssh -S /tmp/mysock lnx0001a -- sleep 3');
system('ssh lnx0001a -- sleep 3');
只要使用“-S/tmp/mysock”变体,ssh就似乎是可中断的,而不是其他方式。有人能解释一下吗?
我应该为此发布一个新的、独立的问题吗
再次感谢
玛兹
更新2:
我把事情弄得更糟了,现在这完全没有任何perl作用域。您可以在shell中执行此操作:
$ trap '' INT
$ ssh lnx0001a -- sleep 3
现在不可中断。
然而,在我的情况下,以下仍然是可中断的:
$ ssh -S /tmp/mysock lnx0001a -- sleep 3
使用CTRL-C,这会立即中断。root用户的情况与我的相同,但其他同事看不到他们的用户有这种行为。我们比较了@ENV,但没有发现可能导致不同行为的原因
您的情况如何?“-S”版本在shell中的“trap”“INT”之后是否可以中断?
(显然,您之前必须为/tmp/mysock创建主会话)
真诚地
Mazze问题在于,当您在控制台上按CTRL-C时,内核会向进程组上的所有进程发送一个信号(请参阅) 我认为您在行为上看到的差异实际上是由子进程上的差异造成的,一些重置了信号标志,而另一些没有 无论如何,我将添加对在不同进程组中运行SSH进程的支持。请在模块上添加错误报告,这样我就不会忘记它 更新:以下实验表明OpenSSH
system
方法和内置的行为方式相同:
my @cmd = $SSH->make_remote_command("sleep 3 && echo hello");
warn "running command @cmd\n";
local $SIG{INT} = 'IGNORE';
system @cmd;
如果运行它,您将看到信号到达并中止ssh
进程,即使INT信号处理程序设置为IGNORE
更新2:经过一些实验,我发现问题实际上在于后台运行的主SSH进程。除非使用密码身份验证,否则它也会挂起在进程组中,因此会获取INT信号
我添加了一个新选项,明确要求将主进程作为一个新的进程组运行,但由于选项太多,这部分代码非常复杂,因此这不是一项容易的任务
更新3:我发布了一个新的模块
现在,你可以做
my $ssh = Net::OpenSSH->new($host, master_setpgrp => 1, ...);
$ssh->system({setpgrp => 1}, "sleep 10; echo uninterruptible");
。。。希望主SSH进程或从SSH进程中不会出现SIGINT
请报告您可能发现的任何问题 在您的情况下,最好通过将Perl_信号的环境变量设置为“不安全”来获得Perl-5.8之前的信号行为 由于Perl 5.8.1,这里描述了信号的正常方法: 但你可能想要的是即时行为,比如: 因此,您的问题的解决方案可能是:
$ENV{'PERL_SIGNALS'} = 'unsafe';
在您的代码中:)
我在这里试过了,到目前为止还有效。但这种方法可能有缺点,因为我不知道您的程序是否会因此面临不同的问题。@Mazze,请参阅我的最新回复。谢谢您的更新2。实际上,我对主会话没有任何问题,主会话似乎尊重我的$SIG{INT}='IGNORE'设置。因此,SIGINT在这里不中断主会话,只中断客户端会话。您不应该依赖于使用继承信号掩码的某个进程。它起作用只是偶然的。无论如何,请参阅我的更新3。更新3和0.61_15已使用新的“setpgrp”标志解决了我的问题。非常感谢您的快速回复。即使在后台打开大量会话(async=>1),也没有问题:)
$ENV{'PERL_SIGNALS'} = 'unsafe';