首先让我说我不想只打印重复的行,也不想删除它们。
我正在尝试将grep与模式文件一起使用来解析大型数据文件。
例如,Pattern文件可能如下所示:
1243
1234
1234
1234
1354
1356
1356
1677
等。包含更多单个和重复条目。
输入数据文件可能如下所示:
aatta 1243 qqqqqq
yyyyy 1234 vvvvvv
ttttt 1555 bbbbbb
ppppp 1354 pppppp
yyyyy 3333 zzzzzz
qqqqq 1677 eeeeee
iiiii 4444 iiiiii
等。为27000行。
当我使用
时grep -f 'Patternfile.txt' 'Inputfile.txt' > 'Outputfile.txt'
我得到一个类似于此的输出文件:
aatta 1243 qqqqqq
yyyyy 1234 vvvvvv
ppppp 1354 pppppp
我怎么能得到它来报告重复项,所以我最终得到这样的东西?:
aatta 1243 qqqqqq
yyyyy 1234 vvvvvv
yyyyy 1234 vvvvvv
yyyyy 1234 vvvvvv
ppppp 1354 pppppp
qqqqq 1677 zzzzzz
此外,如果模式文件中的查询与输入文件中的子字符串不匹配,我还想打印一个空白行。
谢谢!
答案 0 :(得分:2)
一种解决方案,不是grep
,而是perl
:
patternfile.txt
和inputfile.txt
包含原始帖子的数据。 script.pl
的下一个内容应该完成这项工作(我假设要匹配的字符串是第二列,否则应该修改为使用regexp
。这种方式更快):
use warnings;
use strict;
## Check arguments.
die qq[Usage: perl $0 <pattern-file> <input-file>\n] unless @ARGV == 2;
## Open input files.
open my $pattern_fh, qq[<], shift @ARGV or die qq[Cannot open pattern file\n];
open my $input_fh, qq[<], shift @ARGV or die qq[Cannot open input file\n];
## Hash to save patterns.
my (%pattern, %input);
## Read each pattern and save how many times appear in the file.
while ( <$pattern_fh> ) {
chomp;
if ( exists $pattern{ $_ } ) {
$pattern{ $_ }->[1]++;
}
else {
$pattern{ $_ } = [ $., 1 ];
}
}
## Read file with data and save them in another hash.
while ( <$input_fh> ) {
chomp;
my @f = split;
$input{ $f[1] } = $_;
}
## For each pattern, search it in the data file. If it appears, print line those
## many times saved previously, otherwise print a blank line.
for my $p ( sort { $pattern{ $a }->[0] <=> $pattern{ $b }->[0] } keys %pattern ) {
if ( $input{ $p } ) {
printf qq[%s\n], $input{ $p } for ( 1 .. $pattern{ $p }->[1] );
}
else {
# Old behaviour.
# printf qq[\n];
# New requirement.
printf qq[\n] for ( 1 .. $pattern{ $p }->[1] );
}
}
像以下一样运行:
perl script.pl patternfile.txt inputfile.txt
并给出下一个输出:
aatta 1243 qqqqqq
yyyyy 1234 vvvvvv
yyyyy 1234 vvvvvv
yyyyy 1234 vvvvvv
ppppp 1354 pppppp
qqqqq 1677 eeeeee
答案 1 :(得分:1)
对于模式而言,你并没有grep
这么多 - 将输入中的数据加入到模式中的数据中。
你可以(大部分)用join
完成这个,这是一个方便的Unix工具,我已经很好地了解了,因为我一直试图解决类似你的问题。
但是有一些小的差异。
首先命令:
join -a 1 -2 2 <(sort Patternfile.txt) <(sort -k2,3 Inputfile.txt)
并解释:
-a 1
表示还包含文件1中的不可加入的行( Patternfile.txt )。我添加了这个,因为你想要包含&#34;空白&#34;无法匹配行的行,这是我能得到的最接近的行。-2 2
表示在字段2上加入文件2(您可以为-1 FIELD
和-2 FIELD
设置字段,默认为字段1)。这是因为您在 Inputfile.txt 中加入的密钥位于第二列<(sort Patternfile.txt)
- 必须在连接字段中对文件进行排序才能使连接正常工作。<(sort -k2,2 Inputfile.txt)
- 将输入文件从键2排序到键2,包括<强>输出:强>
1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1243 aatta qqqqqq
1354 ppppp pppppp
1356
1356
1677 qqqqq eeeeee
<强>差异强>
指定输出与此结果之间的差异很小:
无法加入的行仍包含其原始密钥。如果这是一个问题,您可以通过简单的awk
管道来清除不匹配的行:
... | awk '{ if ($2 != "") print; else print "" }'