我需要逐行比较两个文件。我只想输出那些不同的行,但在确定差异时,应忽略字符 4-6 和 10-12。没有特定的字段分隔符等。
例子:
- 文件1
abc123def999 ghi456klm999 nop789qrs999
- 文件2
abc000def000 xxx000yyy000 nop000qrs000
在该示例中,只有第二行应该不同。
我不希望read
循环逐行解析文件,因为文件有数百万条记录。
答案1
使用 GNU awk 作为 FIELDWIDTHS 参数:
$ paste file[12] |
awk -v FIELDWIDTHS='3 3 3 3 1 3 3 3 3' '$1!=$6 || $3!=$8'
ghi456klm999 xxx000yyy000
这里我们使用paste
命令并排粘贴两个文件;然后假设两个文件中的行都是固定长度,因为我们使用 awk 的 FIELDWIDTHS 参数来定义字段长度,然后我们比较相关字段的差异;这里的比较是逐行进行的。
或者在任何 shell 中使用任何 awk:
$ paste file[12] |
awk 'function key(s){return substr(s,1,3) substr(s,7,3)} key($1) != key($2)'
ghi456klm999 xxx000yyy000
答案2
您没有显示预期的输出,也没有真正告诉我们您的要求是什么,所以这里是您可能想要的一种猜测,在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
{ key = substr($0,1,3) substr($0,7,3) }
NR == FNR {
a[key]
next
}
!(key in a)
$ awk -f tst.awk file1 file2
xxx000yyy000
$ awk -f tst.awk file2 file1
ghi456klm999
答案3
两个文件都有“数百万条记录”?选择较短的文件,读取每一行,生成一个以“ ^
”(行开头)开头、以“ $
”(行结尾)结尾的正则表达式,搜索字符串位于其间。将要忽略的位置设置为“ .
”(正则表达式“匹配任何单个字符”)。例如“ ^abc...def...$
”。将其保存在临时文件中 ( file1.tmp
)(数百万?)。当您处理完所有行后,将在ingrep -E -f file1.tmp file2
中搜索正则表达式。file1.tmp
file2
答案4
方法-1)perl
该unpack
函数最适合这种情况,根据 perl 环境托盘上提供的格式提取特定的字符范围。(A3x3)2A*
=> 选择三个 ASCII 字符,然后跳过三个字符。再次重复这个过程,然后抓住剩下的东西。
fmt='(A3x3)2A*' \
perl -nse 'print if "@{[unpack($ENV{fmt})]}" ne
"@{[unpack($ENV{fmt},scalar(<STDIN>))]}";
' -- -\"= File1 < File2
ghi456klm999
方法-2)paste+GNU sed
粘贴将两个文件中的相应行并排放置并用制表符分隔。因此,我们假设文件中不应有选项卡。然后我们将两个文件的数据中的 4-6、10-12 个字符替换为相同的字符“.”。在比较线路之前。当 Ines 不匹配时,打印 file1 行。
# helper vars aid in writing sed code
x3='...'
A3="($x3)"
A3x3=$A3$x3
srch="^$A3x3$A3x3"
repl="\\1$x3\\2$x3"
paste File1 File2 |
sed -En 'y/\t/\n/;h
'"s/$srch/$repl/Mg"'
/^(.*)\n\1$/d;g;P
' -
方法-3)Python
内置 zip 函数会并排查看两个文件的行。
python3 -c 'import sys
# skip chars: 4-6 10-12
AoT = [(0,3),(6,9),(12,None)] # array of tuples
fx = lambda t: \
a[t[0]:t[1]] != b[t[0]:t[1]]
ifile1,ifile2 = sys.argv[1:]
with open(ifile1) as f1,\
open(ifile2) as f2:
for a,b in zip(f1,f2):
if any(map(fx,AoT)):
print(a,end="")
' File1 File2