这实际上对我有用,但突然间它停止工作。现在坚持了一个小时,但仍然不知道为什么。
我有
system("ssh -t machine command > stdout.log 2> error.log &")
始终收到错误Pseudo-terminal will not be allocated because stdin is not a terminal
=== UPDATE ===
我已经尝试-T
(这根本不会给我任何错误)和-t -t
而不是-t
并且不会在error.log中指示错误
=== MORE UPDATE ===
-t -t
和-tt
给出了错误“tcgetattr:设备serverCmd ='ssh -x -n machine'的不适当的ioctl,我的目标程序根本没有启动。
只要&
qx
或使用Pseudo-terminal will not be allocated because stdin is not a terminal
即会向我发送同样的错误-t
答案 0 :(得分:0)
短使用fork + exec(推荐),或使用管道打开,或删除-t
伪终端
这里有很多事情要发生。您启动ssh
,需要处理(伪)终端业务,处理流 - 以及后台进程。这是最后一点让它变得棘手。我得到了和你一样的行为。
以下是三个适用于我的解决方案/解决方法。我推荐第一个。
&
的要点是你的脚本立即获得控制权。我们可以很好地在脚本中实现这一点。这更清晰,并不依赖于系统细节。所以放下&
并自己将(ssh)进程放在后台。
use warnings;
use strict;
my $cmd = 'ssh -t machine command >stdout.log 2>error.log';
my $pid = fork;
die "Can't fork: $!" if not defined $pid;
if ($pid == 0) { # child
exec($cmd);
die "exec shouldn't have returned: $! ";
}
# Parent only. Child became $cmd, which went its own way, never to return.
# Rest of your code, executed right away ...
error.log
可能包含行Connection to machine closed.
(它适用于我)。如果需要,fork + exec的基本解释就在最后。
以下是可能存在问题的解决方法,可能无法在任何地方使用,但它们可以实现我的测试所需。
如果command
不需要控制tty drop -t
。重定向和&
仍适用于我。
通过使用管道打开启动(ssh)进程来解决STDIN
问题
my $cmd = 'ssh -t machine command >stdout.log 2>error.log &';
my $pid = open my $fh, '|-', $cmd // die "Can't fork: $!;
# your other code ...
close $fh;
这个'打开'(分叉)执行$cmd
的进程,以便$fh
是STDIN
,我们的脚本可以根据需要提供输入。所以我们提供STDIN
和ssh的伪终端没问题。如果该命令不需要输入,您可以忽略该命令,其余部分根据需要工作。
这是一种非常干净的方法,可以将另一个进程和管道分配到其STDIN
或STDOUT
,或者从$pid
或if ($pid == 0) { }
分配,请参阅教程perlopentut
,参考open
以及更多详细信息Safe Pipe Opens in perlipc
。但是,在这种情况下,我宁愿选择上面的fork + exec。
fork
创建一个新进程并返回其ID。这个新进程是父进程的一个克隆,除了对于该进程,if
为零,而对于父进程,它是一个(大)整数。 (还有一些其他小得多的差异。)因此,孩子确实进入下一个ssh
区块,而父组则没有。这样我们就可以分开子节点和父节点,因此每个节点都可以运行专用于它们的代码。我们得到了并行执行(原则上,也主要是在实践中)。
在exec
块内,子进程执行的程序被exec
执行的程序完全替换,在本例中由if
命令执行。 import commands
iStat, askpassPath = commands.getstatusoutput("which ssh-askpass")
cmd = "export SUDO_ASKPASS=%s;sudo -A mkdir -p /usr/lib/test"%(askpassPath)
commands.getstatusoutput(cmd)
根本不会返回(除非调用本身失败)。父进程继续在static
之后运行,正常执行任何没有阻塞的代码。通过这种方式,我们分拆了另一个程序,而您的程序可以继续其业务,而无需等待另一个程序完成。