查找模式和提取固定位置字段的Perl命令

7rfyedvj  于 2022-12-19  发布在  Perl
关注(0)|答案(3)|浏览(140)

我有这样的文件

FHEAD0000000001RTLG202106182103132021061430914  
THEAD0000000002100  202106141001180000000310  
TITEM  
THEAD  
TITEM  
FTAIL

我想从FHEAD记录中提取商店和营业日期文件中只有一条FHEAD记录
商店从位置41开始-FHEAD RECORD上的5位数字营业日期从位置33开始-FHEAD RECORD上的8位数字
我试过不服从命令

perl -lne ' ($s, $d) = (substr($_, 41, 5), substr($_, 33, 8)) if /FHEAD/; print "$ARGV,$s,$d"; ' $file

但它循环遍历文件中的所有记录,并打印多行而不是一行。我得到的输出为:然而,应该只有一行

RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
RTLOG_OMS_30914_20210618210313_71111119.dat.2,30914,20210614
wqlqzqxt

wqlqzqxt1#

substr和regex的答案都很好,但是有一个经常被忽视的工具叫做unpack
格式说明符在pack文档中。A是一个ASCII字符,后面的数字是它的长度。因此,A5是接下来的五个ASCII字符。每个说明符产生一个列表项。A28跳过填充项以到达正确的位置,然后A8获得日期,A5获得存储。

#!/usr/bin/perl
use v5.10;

while( <DATA> ) {
    next unless /\AFHEAD/;
    my( $header, $fill, $date, $store ) = unpack 'A5 A28 A8 A5', $_;

    say "DATE: $date";
    say "STORE: $store";
    last;
    }

__END__
FHEAD0000000001RTLG202106182103132021061430914
THEAD0000000002100 202106141001180000000310
TITEM
THEAD

这产生:

DATE: 20210614
STORE: 30914

即使你不想使用pack,请注意,我做了另一件事,你可以将其合并到其他答案中。跳过行,直到你找到你想要的行,然后处理该行并终止循环。一旦你找到了该行,你就不需要查看任何其他行了。
作为一个一行程序,它可能类似于下面这样,使用x说明符跳到绝对位置:

% perl -lne 'next unless /\AFHEAD/; print join "\t", unpack q(x33 A8 A5); last' file.txt
20210614    30914

当您处理更多字段时,这会变得更有趣。

nom7f22z

nom7f22z2#

您的打印是无条件的。您只想在以下行匹配时打印:

perl -lne ' print $ARGV,substr($_, 41, 5), substr($_, 33, 8) if /FHEAD/;' file
knpiaxh1

knpiaxh13#

请查看以下命令是否生成所需的输出

perl -lne 'print "date=$1 store=$2" if /FHEAD.{28}(.{8})(.{5})/' file

产出

date=20210614 store=30914

相关问题