Как я могу отобразить статус выполнения команды "ssh-copy-id" из Perl? - PullRequest
1 голос
/ 20 августа 2009

У меня есть Perl-скрипт, который делает это: он генерирует ключ аутентификации ssh в моей системе, а затем копирует этот ключ в удаленную систему Linux для парольных соединений ssh. Код как ниже:

# 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», а если копирование не удалось, отобразить «Не удалось скопировать» и, если оно удалось, отобразить «Копирование выполнено».

Как мне это сделать?

Еще один (на основании ответа Часа):
Я попробовал код, как предложил Час
умри "не мог раскошелиться: $!" если не определено (мой $ pid = fork);

# ребенок спит, затем выходит со случайным кодом выхода
если ($ pid) {
распечатать «Подключение к серверу»; exec "ssh-copy-id -i /root/.ssh/id_rsa.pub $ uname \ @ $ ip 2> & 1 1> / dev / null";
выход int rand 255;
}

# родитель ждет, пока ребенок закончит
$ | = 1;
распечатать "ожидание:";
мой @throbber = qw /. o O o. /;
до ($ pid = waitpid (-1, WNOHANG)) {
# получить следующий кадр
мой $ frame = shift @throbber;

#display it<br />
print $frame;


# введите его в конец списка кадров
push @throbber, $ frame;

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

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

}

Проблема в следующем:
Теперь ssh-copy-id запрашивает ввод пароля при подключении к удаленному серверу. Таким образом, вывод «пульсирующего» (то есть отображаемого круга различного размера) происходит после ввода пароля, что выглядит странно. Вот как это выглядит:
ТЕКУЩИЙ ВЫХОД
Подключение к удаленному серверу o0O0o # Это пульсатор. Вывод не совсем так, но я не могу напечатать динамически изменяемый вывод, могу ли я
Пароль: o0O0oXXXXXo0O0o # Вы правильно поняли, пульсатор неоправданно приходит и в приглашении пароля

ВЫХОД, КОТОРЫЙ Я ХОЧУ:
Подключение к удаленному серверу o0O0o # Пульсирующее устройство должно отображаться ЗДЕСЬ ТОЛЬКО, НИГДЕ ДРУГОЕ
Пароль: XXXXX

Есть идеи, кто-нибудь?

Ответы [ 3 ]

3 голосов
/ 20 августа 2009

Довольно просто отключить другой процесс, чтобы выполнить работу за вас, в то время как основной процесс позволяет пользователю узнать, что вещи не прекратились:

#!/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";
2 голосов
/ 20 августа 2009

system () возвращает состояние завершения программы, возвращаемое ожидающим вызовом. Ничего не возвращается, если системный вызов был успешным.

Таким образом, вы можете увидеть код, подобный этому:

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

Я бы пошел с этим методом. Но было бы неправильно с моей стороны не упомянуть метод, предложенный в книге Best Perl :

use Perl6::Builtins qw( system );

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

Однако обратите внимание, что список рекомендаций PBP указывает на то, что вы не можете использовать autodie :

use autodie qw( system );

eval { system 'ls' };
die "Unable to run ls: $@" if $@;

Так что это, вероятно, канонический путь, идущий вперед.

1 голос
/ 20 августа 2009

Я не думаю, что можно просто (без использования разветвления, таймеров и прочего) добавить индикатор выполнения к одной внешней команде, выполняемой через system (), которая не генерирует вывод.

С другой стороны, я думаю, причина того, что ваш ssh-copy-id занимает много времени, заключается в неправильной настройке DNS (для получения подсказки проверьте журналы sshd на стороне сервера). Сервер ssh, вероятно, пытается разрешить обратное сопоставление для IP-адреса клиента и время ожидания истекло. Исправление этого, вероятно, значительно ускорит процесс.

Когда дело доходит до ваших сообщений. Разве вы не можете просто использовать print перед тем, как запускать команду system () и использовать возвращаемое значение из системы, чтобы напечатать сообщение о завершении (как уже предлагалось в некоторых других ответах)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...