Net::OpenSSH; rsync_put 将进度写入文件,scp_put 不会
Net::OpenSSH; rsync_put writes progress into file, scp_put doesn't
rysnc_put
和 scp_put
都在终端中显示进度。
但是当我尝试将其写入文件时,我只能看到 rysnc_put
的进度。即使我只是打印 pty [我的编辑] 的输出,问题仍然存在。
这是我 pty
用法的问题吗?
仅针对 scp_put
提到,当 STDOUT
不是 tty
时没有进展。
Note that scp will not generate progress reports unless its stdout stream is attached to a tty.
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
my $SSH = Net::OpenSSH->new(
'192.168.178.33',
(
user => 'TT',
password => 'TTpassword',
port => '22',
)
);
my $pty = new IO::Pty;
my $slave = $pty->slave;
$SSH->scp_put(
{
quiet => 0,
verbose => 1,
stdout_fh => $pty,
stderr_fh => $pty,
bwlimit => '200',
},
'/opt/TT/CHANGES.md',
'/opt/TT/CHANGES.md',,
);
while (<$pty>) {
print STDOUT "$_";
}
即使 scp_put
和 rsync_put
是相似的方法,它们包装了两个不相关的程序(scp
和 rsync
),就此而言,它们不会在同理。
具体来说,scp
检查它的 stdio 流是否附加到 pty,如果没有,它会抑制进度消息。据我所知,该功能无法禁用。
更新:并行读取 PTY:
此代码从 PTY 读取数据并将数据并行写入文件:
use strict;
use warnings;
use Net::OpenSSH;
use POSIX ();
use IO::Pty;
my $ssh = Net::OpenSSH->new("localhost"); #, scp_cmd => "/home/salva/t/openssh-8.9p1/scp");
my $pty = new IO::Pty;
my $slave = $pty->slave;
print "slave: $slave, fd: ".fileno($slave)."\n";
my $logger_pid = fork;
unless ($logger_pid) {
defined $logger_pid or die "fork failed: $!";
open my $log, ">", "/tmp/scp.log";
select $log;
$| = 1;
print("Reading from PTY\n");
while (1) {
my $buffer;
sysread($pty, $buffer, 1);
syswrite($log, $buffer, 1);
}
print "PTY closed unexpectedly\n";
POSIX::_exit();
}
my $scp_pid = fork;
unless($scp_pid) {
defined $scp_pid or die "fork failed: $!";
$pty->make_slave_controlling_terminal();
$ssh->scp_put({stdout_fh => $slave,
stderr_fh => $slave,
quiet => 0},
"/etc/passwd", "/tmp/foo.vdi");
}
waitpid($scp_pid, 0);
kill 9, $logger_pid;
waitpid($logger_pid, 0);
您的问题的另一种解决方案是自定义可从 Net::SSH::Any 获得的 SCP 协议的纯 perl 实现。
我从那个包中设计了 SCP 类 进行子类化,这样就可以完成类似的事情,但从来没有真正记录 API,所以,好吧,你会依赖未记录的功能(不过,我不打算更改它)。
use strict;
use warnings;
package MyPutter {
use parent 'Net::SSH::Any::SCP::Putter::Standard';
use Data::Dumper qw(Dumper);
for my $name (qw(open_dir open_file close_file close_dir)) {
my $method = $name;
my $super = Net::SSH::Any::SCP::Putter::Standard->can($name);
no strict 'refs';
*$name = sub {
my ($putter, $a) = @_;
print STDERR "$method $a->{path} --> $a->{local_path}\n";
$super->(@_);
};
}
sub read_file {
my $putter = shift;
my $a = shift;
my $data = $putter->SUPER::read_file($a, @_);
$a->{bytes_copied} += length($data);
print STDERR "read_file $a->{path} --> $a->{local_path} $a->{bytes_copied}/$a->{size}\n";
return $data;
}
};
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new("localhost");
my $any = $ssh->any;
my $putter = MyPutter->_new($any, {}, "/tmp/out2", "/tmp/passwd3");
$putter->run({})
rysnc_put
和 scp_put
都在终端中显示进度。
但是当我尝试将其写入文件时,我只能看到 rysnc_put
的进度。即使我只是打印 pty [我的编辑] 的输出,问题仍然存在。
这是我 pty
用法的问题吗?
仅针对 scp_put
提到,当 STDOUT
不是 tty
时没有进展。
Note that scp will not generate progress reports unless its stdout stream is attached to a tty.
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
my $SSH = Net::OpenSSH->new(
'192.168.178.33',
(
user => 'TT',
password => 'TTpassword',
port => '22',
)
);
my $pty = new IO::Pty;
my $slave = $pty->slave;
$SSH->scp_put(
{
quiet => 0,
verbose => 1,
stdout_fh => $pty,
stderr_fh => $pty,
bwlimit => '200',
},
'/opt/TT/CHANGES.md',
'/opt/TT/CHANGES.md',,
);
while (<$pty>) {
print STDOUT "$_";
}
即使 scp_put
和 rsync_put
是相似的方法,它们包装了两个不相关的程序(scp
和 rsync
),就此而言,它们不会在同理。
具体来说,scp
检查它的 stdio 流是否附加到 pty,如果没有,它会抑制进度消息。据我所知,该功能无法禁用。
更新:并行读取 PTY:
此代码从 PTY 读取数据并将数据并行写入文件:
use strict;
use warnings;
use Net::OpenSSH;
use POSIX ();
use IO::Pty;
my $ssh = Net::OpenSSH->new("localhost"); #, scp_cmd => "/home/salva/t/openssh-8.9p1/scp");
my $pty = new IO::Pty;
my $slave = $pty->slave;
print "slave: $slave, fd: ".fileno($slave)."\n";
my $logger_pid = fork;
unless ($logger_pid) {
defined $logger_pid or die "fork failed: $!";
open my $log, ">", "/tmp/scp.log";
select $log;
$| = 1;
print("Reading from PTY\n");
while (1) {
my $buffer;
sysread($pty, $buffer, 1);
syswrite($log, $buffer, 1);
}
print "PTY closed unexpectedly\n";
POSIX::_exit();
}
my $scp_pid = fork;
unless($scp_pid) {
defined $scp_pid or die "fork failed: $!";
$pty->make_slave_controlling_terminal();
$ssh->scp_put({stdout_fh => $slave,
stderr_fh => $slave,
quiet => 0},
"/etc/passwd", "/tmp/foo.vdi");
}
waitpid($scp_pid, 0);
kill 9, $logger_pid;
waitpid($logger_pid, 0);
您的问题的另一种解决方案是自定义可从 Net::SSH::Any 获得的 SCP 协议的纯 perl 实现。
我从那个包中设计了 SCP 类 进行子类化,这样就可以完成类似的事情,但从来没有真正记录 API,所以,好吧,你会依赖未记录的功能(不过,我不打算更改它)。
use strict;
use warnings;
package MyPutter {
use parent 'Net::SSH::Any::SCP::Putter::Standard';
use Data::Dumper qw(Dumper);
for my $name (qw(open_dir open_file close_file close_dir)) {
my $method = $name;
my $super = Net::SSH::Any::SCP::Putter::Standard->can($name);
no strict 'refs';
*$name = sub {
my ($putter, $a) = @_;
print STDERR "$method $a->{path} --> $a->{local_path}\n";
$super->(@_);
};
}
sub read_file {
my $putter = shift;
my $a = shift;
my $data = $putter->SUPER::read_file($a, @_);
$a->{bytes_copied} += length($data);
print STDERR "read_file $a->{path} --> $a->{local_path} $a->{bytes_copied}/$a->{size}\n";
return $data;
}
};
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new("localhost");
my $any = $ssh->any;
my $putter = MyPutter->_new($any, {}, "/tmp/out2", "/tmp/passwd3");
$putter->run({})