2009-08-20 44 views
1

我有一個Perl腳本,它執行此操作:它會在我的系統上生成一個ssh身份驗證密鑰,然後將此密鑰複製到遠程Linux系統以獲得無密碼ssh連接。代碼如下:如何從Perl中顯示命令「ssh-copy-id」的執行狀態?

# Generate an rsa key and store it in the given file 
system("ssh-keygen -t rsa -N '' -f /root/.ssh/id_rsa 1>/dev/null"); 

# Copy the generated key to a remote system whose username 
# is stored in variable $uname and IP address is stored in variable $ip 
system("ssh-copy-id -i /root/.ssh/id_rsa.pub $uname\@$ip 2>&1 1>/dev/null"); 

我的問題是這樣的:ssh-copy-id命令需要相當一段時間的密鑰複製到遠程系統。所以,當這個Perl腳本運行時,它會像腳本掛起一樣。

因此,我想要顯示一個「進度信息」:當正在進行復制時,我想顯示「SSH驗證密鑰副本正在進行」,如果複製失敗,顯示「無法複製」,如果它已成功顯示「複製成功」。

我該如何去做這件事?

還有一個(基於查斯的回答):
我試過代碼查斯建議
死「無法fork:$!」除非定義(my $ pid = fork);

然後#child睡退出與隨機退出代碼
除非($ PID){
打印 「連接到服務器」; exec「ssh-copy-id -i /root/.ssh/id_rsa.pub $ uname \ @ $ ip 2> & 1 1>/dev/null」;
exit int rand 255;
}

#parent等待孩子完成
$ | = 1;
print「waiting:」;
my @throbber = qw /。 o O o。 /;
直到($ pid = waitpid(-1,WNOHANG)){
#get下一幀
my $ frame = shift @throbber;

#display it<br /> 
print $frame; 


#put它在幀
推@throbber,$幀的列表的末尾;

#wait a quarter second<br /> 
select undef, undef, undef, .25;<br /> 

#backspace over the frame<br /> 
print "\b";<br /> 

}

問題是這樣的:
現在的ssh-copy-id命令要求輸入密碼的輸入,同時連接到遠程服務器。所以,輸入「throbber」(即得到顯示的不同大小的圓圈)出現在密碼輸入之後,看起來很奇怪。這是它的樣子:
當前輸出
連接到遠程服務器o0O0o#這是跳動者。輸出並不完全是這樣,但我不能動態地改變打印輸出,可我
密碼:o0O0oXXXXXo0O0o#你得到它的權利,該活動指示器來不必要的密碼提示過

輸出,我旺旺:
連接到遠程服務器o0O0o #The活動指示器應顯示在這裏只,無處
密碼:XXXXX

任何想法,任何人嗎?

+1

多久可以它可能會採取複製SSH密鑰到一些遠程系統?即使通過撥號線路? – innaM 2009-08-20 12:41:43

+0

@Manni你顯然從未遇到過dns-reverse-lookup和GSSAPIAuthentication問題。我不得不坐下來等待一段時間才能連線。 – 2009-08-20 14:14:32

+0

爲什麼靠近我的.ssh/config文件頂部的一行說「GSSAPIAuthentication no」是有原因的。 – innaM 2009-08-26 19:15:31

回答

3

這是相當簡單的,而主要的過程讓用戶知道事情並沒有停止發生在叉掉另一個進程來爲你做的工作:

#!/usr/bin/perl 

use strict; 
use warnings; 

use POSIX ":sys_wait_h"; 

die "could not fork: $!" unless defined(my $pid = fork); 

#child sleeps then exits with a random exit code 
unless ($pid) { 
    #your code replaces this code 
    #in this case, it should probably just be 
    #exec "ssh-copy-id -i /root/.ssh/id_rsa.pub $uname\@$ip 2>&1 1>/dev/null"; 
    #as that will replace the child process with ssh-copy-id 
    sleep 5; 
    exit int rand 255; 
} 

#parent waits for child to finish 
$| = 1; 
print "waiting: "; 
my @throbber = qw/ . o O o . /; 
until ($pid = waitpid(-1, WNOHANG)) { 
    #get the next frame 
    my $frame = shift @throbber; 

    #display it 
    print $frame; 

    #put it at the end of the list of frames 
    push @throbber, $frame; 

    #wait a quarter second 
    select undef, undef, undef, .25; 

    #backspace over the frame 
    print "\b"; 
} 
#exit code is in bits 8 - 15 of $?, so shift them down to 0 - 7 
my $exit_code = $? >> 8; 
print "got exit code of $exit_code\n"; 
+0

很酷的答案!謝謝! – Ninja 2009-08-21 05:47:33

2

system()返回等待調用返回的程序退出狀態。如果系統調用成功,則不會返回任何內容。

因此u能看到這樣的代碼:

system('ls') and die "Unable to call ls: $?"; 

這是非常直觀;-)

我通常做到以下幾點:

my $status = system('ls'); 
die "Unable to call ls: $?" if $status; 

但是,如果你看的perldoc你會看到一個更好的選擇:

system('ls') == 0 
    or die "Unable to call ls: $?" 

我會用這種方法去。不過,這將是有毛病我不提方法在Perl Best Practices書建議:

use Perl6::Builtins qw(system); 

system 'ls' or die "Unable to run ls: $?"; 

但是,請注意PBP recommendation list點,你離開這對使用autodie

use autodie qw(system); 

eval { system 'ls' }; 
die "Unable to run ls: [email protected]" if [email protected]; 

所以這可能是典型前進的道路。

1

我不認爲這是可能的一個簡單的方法(無需訴諸分叉,定時器和whatnot)添加一個進度條到一個單一的外部命令運行通過system()不會產生輸出。

另一方面,我認爲你的ssh-copy-id花費很長時間才能完成的原因是因爲DNS設置不正確(請檢查服務器端的sshd日誌以獲取線索)。 ssh服務器可能會嘗試解析客戶端IP的反向映射並超時。修復這可能會加速很多事情。

談到您的消息。在運行system()命令並使用系統的返回值打印完成消息(正如其他一些答案所建議的)之前,您不能僅僅使用打印文件?

+0

是的,這會讓事情複雜:) – Ninja 2009-08-20 13:34:33