如果不匹配,我如何逐行比较两个文本文件和打印错误?

时间:2014-07-30 09:18:36

标签: perl

让我简要介绍一下我尝试做的事情,因为现在我的脚本正在将文件从SFTP拉到本地系统。拉动时确保文件没有损坏。所以我需要确保file size完全相同。从SFTP中提取文件后,我将file sizefilename打印到filename.txt,如下所示。我这样做是因为我尝试比较这两个文本文件以确保没有文件被破坏。

Filename.txt

7 hankeong_test.txt
3 hankeong_test2.txt
10753 hankeong_test3.txt

但是,SFTP命令是有限的。它不仅可以显示SizeFile name,我可以使用的唯一命令是ls -l *.txt。以下是SFTP到input.txt的输出。

input.txt中

-rwxr-xr-x     512      501             7 Jul 24 17:54 hankeong_test.txt
-rwxr-xr-x     512      501             3 Jul 25 11:32 hankeong_test2.txt
-rwxr-xr-x     512      501         10753 Jul 24 17:54 hankeong_test3.txt
sftp> ls -l *.txt
sftp> quit

如果这两个文件有两种不同的格式,我如何比较这两个文件?

预期产出:

代码可以逐行比较两个文件并查看该行是否正确,如果不正确,它会向用户打印出ERROR消息。

我正在使用Windows 7和SSH tectia访问SFTP。

任何建议或其他更好的解决方案?谢谢!

4 个答案:

答案 0 :(得分:1)

一般来说,解析ls并不是一个好主意:例如,请参阅this question。也就是说,您可以使用这样的东西来比较两个列表:

use strict;
use warnings;
use autodie;

my ($files, $ls) = ($ARGV[0], $ARGV[1]);
open my $fh_files, "<", $files;
open my $fh_ls, "<", $ls;

my %sizes;
while (<$fh_files>) {    
    # regex assumes filenames contain no spaces
    if (my ($size, $name) = /^(\d+)\s+(\S+)$/) {
        $sizes{$name} = $size;
    }
}

while(<$fh_ls>) {
    # if output is tab-delimited, use split /\t/
    my @cols = split;
    my ($size, $name) = ($cols[3], $cols[7]);

    if (!defined $sizes{$name}) { 
        print "$name: file exists locally but not on device\n";
    }
    elsif ($sizes{$name} != $size) {
        print "$name has incorrect size\n";
        print "size on host: $size\n";
        print "local size: $sizes{$name}\n";
    }
}

close $fh_files;
close $fh_ls;

使用它:perl filelist_compare.pl Filename.txt input.txt

答案 1 :(得分:0)

我建议使用文件的md5摘要而不是文件大小。如果您有sftp访问权限,则可能还具有ssh访问权限。如果是这样,请在远程服务器上尝试以下操作并在本地进行相同操作将输出保存在两个文件中,然后与diff进行比较:

openssl md5 *.txt
MD5(hankeong_test.txt)= 0bee89b07a248e27c83fc3d5951213c1
MD5(hankeong_test2.txt)= 614dd0e977becb4c6f7fa99e64549b12
MD5(hankeong_test3.txt)= b6273b589df2dfdbd8fe35b1011e3183

答案 2 :(得分:0)

我敢提到使用MD5或SHA哈希或unix sum命令来确定文件的有效性吗?

答案 3 :(得分:0)

至少有两种更好的方法:

  1. 使用rsync代替SFTP,传输并检查本地和远程文件是否完全相同。

  2. 使用一些用于SFTP的Perl模块执行传输(例如,Net::SFTP::Foreign)。您将能够在发生传输错误时处理它们,并且还可以轻松地查询远程文件系统。