2009-08-20 3 views
1

필자는이 작업을 수행하는 Perl 스크립트를 가지고 있습니다. 시스템에서 ssh 인증 키를 생성 한 다음이 키를 암호가없는 ssh 연결을 위해 원격 Linux 시스템에 복사합니다. 코드는 다음과 같습니다 : 내가 가지고있는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 인증 키 복사 진행 중"을 표시하고 복사가 실패하면 "복사 실패"를 표시합니다. 그것은 성공했으며 "Copy succeeded"라고 표시합니다.

어떻게해야합니까?

하나 더 (차스의 답변에 따라) : 차스이
다이를 제안
나는 코드를 시도했다 "포크 없습니다! $를" 정의되지 않은 한 (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;
인쇄 "대기 :";
my @throbber = qw /. o O o. /; ($ waitpid를 PID = (-1, WNOHANG)) {다음 프레임
내 $ 프레임 = 시프트 @throbber #get

까지 ;

프레임 푸시 @throbber, $ 프레임리스트의 마지막에 #put

#display it<br /> 
print $frame; 


; 원격 서버에 연결하는 동안
지금 복사 SSH-ID가 패스워드 입력을 요구 :

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

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

}

문제는이된다. 따라서 "throbber"출력 (즉, 다양한 크기의 원이 표시됨)은 암호 입력 이후에 나타나며 이상하게 보입니다. 이것은 다음과 같습니다 :
현재 출력
원격 서버에 연결 o0O0o # 이것은 진동합니다., 출력은 정확히처럼 보이지 않는하지만 난 출력을 변경 동적으로 인쇄 할 수 있습니다 I
암호 : o0O0oXXXXXo0O0o #You은 바로, 색인기를 불필요하게 암호에 온다 너무

출력을하라는 메시지가 얻을 I 원하는 :
는 원격 서버 o0O0o #The에 연결 여기 만 표시되어야 색인기, 다른 곳
암호 : XXXXX

모든 아이디어, 사람
?

+1

이 얼마나 오래 가능성이 SSH 키를 복사하기 위해 취할 수있는 어떤 원격 시스템에? 전화 접속 회선을 통해조차? – innaM

+0

@Manni 분명히 dns-reverse-lookup 및 GSSAPIAuthentication 문제가 발생하지 않았습니다. 나는 앉아서 잠시 기다려야했다. –

+0

내 .ssh/config 파일의 맨 위에있는 행에 "GSSAPIAuthentication no"라는 이유가 있습니다. – innaM

답변

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

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: $?" 

이 방법으로 갈 것입니다. 그래서 아마 정규이다

use autodie qw(system); 

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

을 :

use Perl6::Builtins qw(system); 

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

그러나 autodie를 사용으로 당신을 멀리이에서 PBP recommendation list 사항을주의 그러나 방법은 Perl Best Practices 책에서 제안 말할 것도없고 나를 나쁘게 될 것이다 앞으로 나아갈 수 있습니다.

1

출력을 생성하지 않는 system()을 통해 실행되는 단일 외부 명령에 진행률 표시 줄을 추가하는 것이 쉬운 방법 (포크, 타이머 및 기타 등등을 사용하지 않고)이라고 생각하지 않습니다.

한편, ssh-copy-id가 완료되는 데 오랜 시간이 걸리는 이유는 부적절한 DNS 설정 (서버 측의 sshd 로그에서 실마리를 확인하십시오) 때문입니다. ssh 서버는 클라이언트 IP에 대한 역 매핑을 해결하고 시간 초과를 시도합니다. 고쳐서하면 일이 상당히 빨라질 것입니다.

메시지에 관해서는. system() 명령을 실행하고 시스템의 반환 값을 사용하여 완료 메시지를 인쇄하기 전에 인쇄물을 사용할 수 없습니까? (다른 답변에서 이미 제안한대로)?

+0

예, 복잡하지 않게됩니다. – Ninja