我正在连接远程主机并执行一个不退出的命令(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文件
host / ip,username,password,command(tail -F / full / path / to / logfile),要保存的文件名
答案 0 :(得分:2)
诀窍是使用-t
(或可能-tt
)调用ssh。
默认情况下,ssh仅在远程计算机上为交互式登录shell分配pty(即,不在远程调用命令时)。 -t
强制ssh分配pty,即使在执行远程命令时也是如此。你可以看到效果:
$ ssh starquake tty
not a tty
VS
$ ssh -t starquake tty
/dev/pts/1
Connection to starquake closed.
ssh apparently will pass on signals to the remote process连接到终端时,但不是。
答案 1 :(得分:0)
如果您知道对tail -f
的调用的进程ID,则可以从命令行向其发送INT
信号:
kill -s INT <pid>
您需要在主程序的$SIG{'INT'}
中执行的操作是让它通过INT
连接发送Net::SSH
。不幸的是,我不知道该怎么做。
答案 2 :(得分:0)
$ SSH-&GT;登录(); #to登录ssh会话
$ ssh - &gt;关闭; #从ssh会话注销
享受。
答案 3 :(得分:0)
在这里,您可以看到使用SFTP而不是SSH连续读取远程文件的替代解决方案:sftp_tail.pl。
远程sftp-server
进程将在连接关闭时退出(例如,因为您按Ctrl-C),而无需您执行任何进一步操作。
答案 4 :(得分:-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;