두 파일에 대해 작업을 수행 diff
하고 첫 번째 차이점에서 중지하고 싶습니다. 물론 명령을 를 통해 수행할 필요는 없지만 diff
첫 번째 차이점이 발견되어 보고되면 실제 명령이 중단되도록 요구합니다. 난 좀 달리고 있어매우대용량 파일을 저장하고 완벽한 일치를 기대하지만 여전히 차이점이 무엇인지 알고 싶습니다. 따라서 diff -q
, diff ... |head -1
및 cmp
는 좋지 않습니다. 그리고 파일 용량이 매우 크기 때문에 메모리를 소모하지 않는 것이 좋을 것 같습니다. 현재 문제에는 필요하지 않지만 첫 번째(사용자 지정) n 차이에 대해 작동하는 솔루션과 공백 차이를 무시할 수 있는 솔루션에 대한 보너스 포인트입니다.
답변1
cmp
첫 번째 차이에서 멈춥니다.
% cat foo
foo
bar
baz
---
foo
bar
baz
% cat bar
foo
bar
baz
---
foo+
bar+
baz+
% cmp foo bar
foo bar differ: byte 20, line 5
%
다른 줄을 인쇄하기 위해 스크립트를 둘러쌀 수 있습니다.
#! /bin/bash
line=$(cmp "$1" "$2" | awk '{print $NF}')
if [ ! -z $line ]; then
awk -v file="$1" -v line=$line 'NR==line{print "In file "file": "$0; exit}' "$1"
awk -v file="$2" -v line=$line 'NR==line{print "In file "file": "$0; exit}' "$2"
fi
% ./script.sh foo bar
In file foo: foo
In file bar: foo+
이제 비용의 일부가 AWK 명령으로 전환되지만 두 파일을 모두 검사하는 것보다 훨씬 빠릅니다.
답변2
나는 이것을 사소한 사례로 테스트했지만 현장 테스트는 여러분에게 맡깁니다.
$ cat f1
l1
l21 l22 l23 l24
l3
l4x
l5
$ cat f2
l1
l21 l22 l23
l3
l4y
l5
$ cat awkdiff.awk
BEGIN {
maxdiff = 5
ignoreemptylines = 1
whitespaceaware = 1
if (whitespaceaware) {
emptypattern = "^[[:space:]]*$"
} else {
emptypattern = "^$"
FS=""
}
f1 = ARGV[1]
f2 = ARGV[2]
rc1=rc2=1
while( (rc1>0 && rc2>0 && diff<maxdiff) ) {
rc1 = getline l1 < f1 ; ++nr1
rc2 = getline l2 < f2 ; ++nr2
if (ignoreemptylines) {
while ( l1 ~ emptypattern && rc1>0) {
rc1 = getline l1 < f1 ; ++nr1
}
while ( l2 ~ emptypattern && rc2>0) {
rc2 = getline l2 < f2 ; ++nr2
}
}
if ( rc1>0 && rc2>0) {
nf1 = split( l1, a1)
nf2 = split( l2, a2)
if ( nf1 <= nf2) {
nfmin = nf1
} else {
nfmin = nf2
}
founddiff = 0
for (i=1; i<=nfmin; ++i) {
if ( a2[i]"" != a1[i]"") {
printf "%d:%d:{%s} != %d:%d:{%s}\n", \
nr1, nf1, a1[i], nr2, nf2, a2[i]
founddiff=1
++diff
break
}
}
if ( !founddiff && nf1 != nf2) {
if ( nf1 > nf2)
printf "%d:%d:{%s} != %d:EOL\n", nr1, nfmin+1, a1[nfmin+1], nr2
else
printf "%d:EOL != %d:%d:{%s}\n", nr1, nr2, nfmin+1, a2[nfmin+1]
++diff
}
} else {
if ( rc1 == -1 && rc2 == -1) {
print "IO error"
} else if ( rc1 == 1 && rc2 == 0) {
print "%d:%s != EOL\n", nr1, l1
} else if ( rc1 == 0 && rc2 == 1) {
printf "EOL != %d:%s\n", nr2, l2
}
}
}
}
$ awk -f awkdiff.awk /tmp/f1 /tmp/f2
2:4:{l24} != 2:EOL
6:1:{l4x} != 5:1:{l4y}
maxdiff = N: 비교가 중지되어야 하는 최대 차이 수를 설정합니다.
ignoreemptylines = 1|0: 비교할 때 빈 줄을 무시해야 하는지 지정합니다.
whitespaceaware = 1|0: 비교를 단어 단위(연속 공백이 같다고 가정) 또는 줄 단위로 수행해야 하는지 지정합니다.