5

リモートホストに接続して、終了しないコマンドを実行しています (tail -f logfile)

ハンドラーを登録し、出力をログ ファイルに書き込みます。これは正常に動作していますが、メイン プログラムで Control+C を押すと、リモート マシンでコマンドが停止し、ssh 接続が適切に閉じられるはずです

だから私はSIGINTのシグナルハンドラーを登録しています

サブルーチンに入れる必要があるコードが必要です

以下のコードは、フォークされた子から呼び出される関数内にあります

#!/ats/bin/perl

use Net::SSH::Perl;
use File::Path;
use Text::CSV_XS;

chomp ($progName = `basename $0`);

if (@ARGV != 1 ) {
        print "usage: perl $progName <tc_id>\n";
        exit;
}

$tc_id = shift;
$file = "config.prop";
$log_dir = "logs/";


#$SIG{INT}=\&close_write;

sub close_write
{
#-- write it to file
print "\nInside END block\n";
#open FH, ">$log_file";
#print $log_file;
#print FH @out;
#$thr->kill('INT');
#close $ssh->sock;
#undef $ssh;
exit 1;
}

# Read the configuration file and populate the Hash
$index = 0;
my $csv = Text::CSV_XS->new ({ binary => 1, eol => $/ });
 open my $io, "<", $file or die "$file: $!";
 while (my $row = $csv->getline ($io)) {
    next if (${$row}[0] =~ m/^#/);  #Ignore comments
    next if (${$row}[0] =~ m/^\s*$/);   #Ignore blank lines
    ($logHashArray->[$index]->{host}, $logHashArray->[$index]->{user}, $logHashArray->[$index]->{pass}, $logHashArray->[$index]->{cmd}, $logHashArray->[$index]->{log_file}) = @$row;
    $index++;
 }


# Append "/" at the end of the directory if it does not exist
unless ($log_dir =~ m/\/$/) {
        $log_dir = $log_dir . "/";
        print "LogDir: $log_dir\n";
        }
# Check if the log directory exists, if not, create it
if (-e $log_dir) {
        unless (-d $log_dir) {
                die "File exists but is not directory";
                }
        }
else {
        # don't forget to check mkdir's failure
        print "Directory $log_dir does not exist... Creating it\n";
        mkpath($log_dir, 0777) or die "Can't make directory: $!";
        }



foreach $logHash (@{$logHashArray}){
        #print "LogHash Index $logHash\n";
        $logHash->{log_file} = $tc_id . "_" . $logHash->{host} . "_" .$logHash->{log_file};
        $logHash->{cmd} = $logHash->{cmd} . " | tee /tmp/" . $logHash->{log_file};
        $logHash->{log_dir} = $log_dir;

        #$logHash->{thr}=threads->new(\&connect_get_logs, $logHash);

        $logHash->{pid} = fork();

        if ($logHash->{pid}){
            # Parent
            push(@childs, $logHash->{pid});
        }
        elsif ($pid == 0){
            # Child
            connect_get_logs($logHash);
        }
        else {
            die "couldn’t fork: $!\n";
            }

while (($key, $value) = each(%{$logHash})){
     print $key."=>".$value."\n";
}

}

#$SIG{INT}=\&close_write;
#$thr=threads->new(\&connect_get_logs, $logHash);

foreach (@childs) {
    waitpid($_, 0);
    }


#print "Waiting...";
#while(1) {sleep 1;}

#$thr->join;


sub connect_get_logs{

$SIG{INT}= sub {
        print "Inside INT block\n"; ### Need proper code here
        close $ssh->sock;
        undef $ssh;
        };

my $logHash = shift;

while (($key, $value) = each(%{$logHash})){
     print $key."=>".$value."\n";
}
my $stdout;
my $stderr;
my $exit;

#-- setup a new connection
print "Logging in to $logHash->{host}...";
my $ssh = Net::SSH::Perl->new($logHash->{host}, debug => 0, protocol => '2', options => ["PasswordAuthentication yes", "BatchMode yes",
                    "PubkeyAuthenticaion no", "RhostsAuthentication no", "RhostsRSAAuthentication no", "RSAAuthentication no", "DSAAuthentication no"]);

#-- authenticate
$ssh->login($logHash->{user}, $logHash->{pass});
print "Logged In\n";

#-- Create or Overwrite the log files
open LOG_FILE, ">", "$logHash->{log_dir}$logHash->{log_file}" or die $!;

#-- register a handler
$ssh->register_handler("stdout", sub {
        my($channel, $buffer) = @_;
        $str = $buffer->bytes;
        #push @out, $str;
        print LOG_FILE $str;
        #print $str;
});

#$SIG{INT}=\&close_write;

#-- execute the command
($stdout, $stderr, $exit) = $ssh->cmd($logHash->{cmd});

print "Error: $stderr";

}

csv 形式で config.prop ファイルを作成する

ホスト/IP、ユーザー名、パスワード、コマンド (tail -F /full/path/to/logfile)、保存するファイル名

4

5 に答える 5

2

トリックは、-t(またはおそらく-tt)でsshを呼び出すことです。

デフォルトでは、ssh は対話型ログイン シェルに対してのみリモート マシンに pty を割り当てます (つまり、リモートでコマンドを呼び出すときは割り当てません)。 -tリモートコマンドを実行しているときでも、ssh に pty の割り当てを強制します。効果を確認できます:

$ ssh starquake tty
not a tty

$ ssh -t starquake tty
/dev/pts/1
Connection to starquake closed.

sshは、端末にアタッチされている場合はリモート プロセスにシグナルを渡すようですが、それ以外の場合は渡しません。

于 2012-11-21T18:36:43.260 に答える
0

$ssh->login(); #ssh セッションにログインするには

$ssh ->閉じる; #ssh セッションからログアウトするには

楽しい。

于 2014-09-30T14:58:03.933 に答える
0

への呼び出しのプロセス ID がわかっている場合は、次のようにコマンド ラインからシグナルをtail -f送信できます。INT

kill -s INT <pid>

メインプログラムで行う必要があるのは、接続を介して$SIG{'INT'}送信することです。残念ながら、私はそれを行う方法がわかりません。INTNet::SSH

于 2012-07-18T12:31:05.880 に答える
0

ここでは、SSH の代わりに SFTP を使用してリモート ファイルから継続的に読み取る代替ソリューションを確認できます: sftp_tail.pl

リモートsftp-serverプロセスは、接続が閉じられると (たとえば、Ctrl-C を押したために) 終了し、それ以上の操作は必要ありません。

于 2014-10-01T07:51:07.733 に答える
-1

perl 内で ssh セッションにログイン、アクセス、および閉じるための完全な手順。

            my $host = 192.168.0.1;

            my $username = "example";

            my $passwd  = "example";

            my $ssh = Net::SSH::Expect->new(
            host => $host,
            user => $username,
            password => $passwd,
            timeout => 20,
            );
            $ssh->login();
            $ssh->exec("command_to_be_executed_in_ssh\r\n");
            $ssh ->close;
于 2014-09-30T15:07:55.713 に答える