如何在执行外部命令时捕获Perl中的大型STDOUT输出

时间:2017-02-16 10:35:36

标签: perl shell sftp

我想获取远程位置中存在的文件名列表。

我在Perl脚本中使用以下代码段。

my $command = "sftp -q -o${transferAuthMode}=yes -oPort=$sftpPort ${remoteUsername}\@${remoteHost} 2>\&1 <<EOF\n" . 
       "cd \"${remotePath}\"\n" . 
       "ls -l \n" . 
       "quit\n" . 
       "EOF\n";

my @files = `$command`;

当远程位置中的文件数量很大(> 500)时,并非所有文件名都在@files中捕获。

当我手动执行SFTP并列出文件时,所有文件都会列出,但我没有通过脚本获得相同的文件。每次@files大小不同。它只在有大量文件时才会发生。

我无法找到背后的原因。你能帮忙吗?

1 个答案:

答案 0 :(得分:2)

这可以在不需要任何额外的封装模块的情况下实现。我在CentOS 7服务器(Windows VM)上进行了测试。

我的远程主机详细信息:我在远程主机目录中获得了~2000个文件。 CentOS 6.8服务器。

%_gaurav@[remotehost]:/home/gaurav/files/test> ls -lrth|head -3;echo;ls -lrth|tail -2
total 7.9M
-rw-rw-r--. 1 gaurav gaurav 35 Feb 16 23:51 File-0.txt
-rw-rw-r--. 1 gaurav gaurav 35 Feb 16 23:51 File-1.txt

-rw-rw-r--. 1 gaurav gaurav 38 Feb 16 23:51 File-1998.txt
-rw-rw-r--. 1 gaurav gaurav 38 Feb 16 23:51 File-1999.txt
%_gaurav@[remotehost]: /home/gaurav/files/test>

来自LocalHost的脚本输出:请注意,我正在运行您的命令,而不是o${transferAuthMode}=yes部分。如下所示,该脚本能够收集数组中的所有结果,大于500个结果。

我正在查看总条目,数组中的一些特定索引号以显示结果,但尝试使用未注释的Dumper行来查看完整结果。

%_STATION@gaurav * /root/ga/study/pl> ./scp.pl
Read 2003 lines from SCP command.

ArrayIndex: 2,3,1999,2000 contain:

[-rw-rw-r--    0 501      501           36B Feb 16 23:51 File-58.txt]
[-rw-rw-r--    0 501      501           37B Feb 16 23:51 File-129.txt]
[-rw-rw-r--    0 501      501           38B Feb 16 23:51 File-1759.txt]
[-rw-rw-r--    0 501      501           38B Feb 16 23:51 File-1810.txt]
%_STATION@gaurav * /root/ga/study/pl>

脚本及其工作:

#!/usr/bin/perl

use strict ;
use warnings ;
use Data::Dumper ;

my $sftp_port=22 ;
my ($user, $host) = ("gaurav","192.168.246.137") ;
my $remote_path = '/home/gaurav/files/test' ;

my @result ;    # To store result

my $command = "sftp -q -oPort=$sftp_port ${user}\@${host} 2>\&1 <<EOF\n"."cd $remote_path\nls -lrth\nquit\nEOF" ;

# open the command as a file handle, read output and store it.
open FH, "$command |" or die "Something went wrong!!\n" ;
while (<FH>) {
  tr/(?\r|\f|\n)//d ; # Removing any new line, carriage return or form feed.
  push(@result,"\[$_\]") ;
}
close FH ;

#print Dumper @result ;

# Just for printing a little bit of results from
# the array. Following lines can be deleted.
my $total = scalar @result ;
print "Read $total lines from SCP command.\n" ;
print "\nArrayIndex: 2,3,1999,2000 contain:\n
$result[2]
$result[3]
$result[1999]
$result[2000]
" ;

另一种方式:也可以通过制作shell脚本并从perl脚本调用它并读取其输出来解决此问题。如下所示,我的shell脚本由perl脚本和最终输出调用。当没有太多时间直接在perl中编写/表达命令时,这可以用作快速技术。 您可以在早期脚本中使用qx样式(如下所示)

Shell脚本“scp.sh”

%_STATION@gaurav * /root/ga/study/pl> cat scp.sh
#!/bin/bash

sftp -oPort=${1} ${2}@${3} 2>&1 <<EOF
cd ${4}
ls -l
quit
EOF

Perl Script“2scp.pl”

%_STATION@gaurav * /root/ga/study/pl> cat 2scp.pl
#!/usr/bin/perl

use strict ;
use warnings ;
use Data::Dumper ;

my $sftp_port=22 ;
my ($user, $host) = ("gaurav","192.168.246.137") ;
my $remote_path = '/home/gaurav/files/test' ;

# Passing arguements to shell script using concatination.
my $command = './scp.sh '." $sftp_port $user $host $remote_path" ;

my @result = qx{$command} ;     # Runs the command and stores the result.
my $total = scalar @result ;
print "Read $total lines from SCP command.\n" ;
# End.

输出:

%_STATION@gaurav * /root/ga/study/pl> ./2scp.pl
Read 2004 lines from SCP command.
%_STATION@gaurav * /root/ga/study/pl>

试试看,告诉我们。 感谢。