簡體   English   中英

Perl的反引號/系統給出“tcsetattr:輸入/輸出錯誤”

[英]Perl's backticks/system giving “tcsetattr: Input/output error”

我正在編寫一個perl腳本,它使用ssh在幾個不同的服務器上啟動腳本。 只要此腳本正在運行,遠程腳本就需要運行:

#!/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的調用;請參閱enter_raw_mode中的sshtty.c ,從enter_raw_mode中的client_loop clientloop.c )。

從IEEE Std 1003.1,2004(Posix) 第11.1.4節:終端訪問控制 ,如果調用進程處於孤立(或背景?), tcsetattr可能返回-1並帶有errno == EIO (即“輸入/輸出錯誤”)過程組。

實際上, ssh正在嘗試更改本地終端的設置,即使它不在前台進程組中(由於你的fork和本地腳本已退出(正如在您的錯誤消息之前出現的明顯的shell提示所證明的那樣)引用輸出))。

如果你只是想避免錯誤消息,你可以使用ssh -ntt (從/ dev / null重定向stdin,但要求遠程端分配tty)而不是ssh -t (添加你的-l和任何其他選項)你需要回來的,當然)。


更有可能的是,只要某些遠程進程仍在運行,您就可以保持本地腳本的運行。 為此,您需要使用wait函數(或其中一個“親戚”)等待每個分叉進程退出,然后退出分叉它們的程序(這將使它們保留在前台進程組中,只要程序它開始了它們。 您可能仍然希望使用-n ,因為如果您分叉的多個ssh實例同時嘗試使用(從本地終端讀取或更改設置),那將會令人困惑。

作為一個簡單的演示,您可以讓本地腳本在分離所有子節點后sleep 30 ,以便ssh命令在它們是前台進程組的一部分時有時間啟動。 這應該可以抑制錯誤消息,但不會解決您的既定目標。 你需要wait (如果我正確地解釋你的目標)。

這可能是因為當stdin / stdout不是真正的ttys時你強迫SSH分配tty。 SSH嘗試在這些處理程序上調用某些特定的tty函數(可能從遠程端轉發),並且調用無法返回一些錯誤。

你有什么理由要分配一個tty嗎?

是否還有任何理由使用SSH協議的過時版本1?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM