Perl的反引号/系统给出“tcsetattr:输入/输出错误”
我正在编写一个perl脚本,它启动几个不同服务器上的脚本使用ssh。远程脚本需要,只要运行,因为这脚本运行:Perl的反引号/系统给出“tcsetattr:输入/输出错误”
#!/usr/bin/perl
require 'config.cfg'
#@servers is defined in config.cfg
#Contains server info as [username,hostname]
#
# @servers = ([username,server1.test.com],[username,server2.test.com])
#
foreach $server (@servers) {
my $pid = fork();
if ($pid == 0) {
$u = ${$server}[0];
$h = ${$server}[1];
print "Running script on $h \n";
print `ssh -tl $u $h perl /opt/scripts/somescript.pl`;
exit 0;
} else {
die "Couldn't start the process: $!\n";
}
}
[...]
当我运行该脚本,我得到下面的输出:
./brokenscript.pl
Server01上运行脚本
$ tcsetattr:输入/输出错误
与server01的连接已关闭。
与system
一起运行时会发生相同的结果(因为我希望输出脚本,反引用是首选。当我在命令行反引号之间运行确切的命令时,它完全按预期工作。这是什么造成的?
的tcsetattr: Input/output error
消息来自SSH当它试图把本地终端到“原始”模式(其涉及到tcsetattr呼叫;参见sshtty.c
enter_raw_mode
,在clientloop.c
从client_loop
调用)。
从IEEE标准1003.1,2004(POSIX)Section 11.1.4: Terminal Access Control,tcsetattr可以返回-1与errno == EIO
(即“输入/输出错误”)如果调用进程是一个孤立的(或背景?)处理组中使用。
有效SSH正在试图改变该本地终端的设置,即使它不是前台进程组中(由于你叉和的,本地脚本离开(通过表观壳提示证明该紧接在引用输出中的错误消息之前))。
如果你只是想避免的错误信息,您可以使用ssh -ntt
(重定向从/ dev/null的标准输入,但要求远程方反正分配一个tty),而不是ssh -t
(添加-l
和任何其他选项,你当然也需要回来)。
更有可能的是,只要某些远程进程仍在运行,您很有可能保持本地脚本运行。为此,您需要使用wait
函数(或其“亲属”之一)等待每个分支进程退出,然后才能退出分支它们的程序(只要程序存在,这将使它们保持在前台进程组中开始他们在里面)。尽管如此,如果您分叉的ssh的多个实例都尝试同时使用(从本地终端读取或更改设置),那么您仍可能仍希望使用-n
。
举一个简单的演示,你可以在本地脚本做sleep 30
分叉了所有的孩子,让该SSH指令(S)有时间来启动,而他们是前台进程组的一部分了。这应该抑制错误信息,但它不会解决您陈述的目标。你需要wait
(如果我正确解释你的目标)。
这可能是因为当标准输入/标准输出不是真正的ttys时,你迫使SSH分配一个tty。 SSH尝试在这些处理程序上调用某些特定的tty函数(可能从远程端转发),并且调用失败返回一些错误。
你有什么理由为什么你应该分配一个tty?
是否有任何理由使用SSH协议的废弃版本1?
星期一我来试试你的建议。在等待:远程脚本永远运行直到它们在这个脚本被杀时被杀死,所以我不认为我需要等待它们。但我将不得不进行调查。 – 2011-05-14 14:39:06