리눅스 터미널에서 두 파일 비교


168

"a.txt""b.txt" 라는 두 파일에는 모두 단어 목록이 있습니다. 이제 "a.txt"에 추가되어 있고 "b.txt"에 없는 단어를 확인하고 싶습니다 .

두 사전을 비교할 때 효율적인 알고리즘이 필요합니다.


27
diff a.txt b.txt충분하지 않다?
ThanksForAllTheFish

각 파일에서 단어가 여러 번 나타날 수 있습니까? 파일을 정렬 할 수 있습니까?
Basile Starynkevitch

"b.txt"에없고 a.txt에있는 단어 만 필요
Ali Imran

답변:


343

vim을 설치 한 경우 다음을 시도하십시오.

vimdiff file1 file2

또는

vim -d file1 file2

환상적입니다.여기에 이미지 설명을 입력하십시오


9
확실히 대단하고, 디자인이 좋고, 차이점을 쉽게 찾을 수 있습니다. Ohmygod
Zen

1
당신의 대답은 굉장하지만, 선생님은 어떤 라이브러리 함수를 사용하지 않는 저를 필요 : P
알리 이므 란

1
정말 좋은 도구입니다! 이것은 매우 도움이됩니다.
user1205577

1
그 색의 의미는 무엇입니까?
zygimantus

1
색상 코드는 두 파일에서 서로 다르다는 것을 의미합니다. @zygimantus
Fengya Li

73

그들을 정렬하고 사용하십시오 comm:

comm -23 <(sort a.txt) <(sort b.txt)

comm(정렬 된) 입력 파일을 비교하고 기본적으로 a에 고유 한 행, b에 고유 한 행 및 둘 다에 존재하는 세 개의 열을 출력합니다. 지정하여 -1, -2및 / 또는 -3당신은 해당 출력을 억제 할 수 있습니다. 따라서 comm -23 a ba에 고유 한 항목 만 나열합니다. <(...)구문을 사용하여 파일을 즉석에서 정렬합니다. 이미 정렬되어 있으면 필요하지 않습니다.


grep 명령 만 사용하여 나만의 답변을 추가했습니다. 더 효율적이라고 말씀해주십시오.
Ali Imran

3
@AliImran comm은 전체 파일을 메모리에 저장하지 않고 단일 실행으로 작업을 수행하므로보다 효율적입니다. 이미 정렬 된 사전을 사용하고 있으므로 사전에 필요하지 않습니다 sort. grep -f file1 file2반면에 사용 하면 전체 file1를 메모리에 로드하고 각 행 file2을 모든 해당 항목 과 비교 하므로 훨씬 덜 효율적입니다. 작고 분류되지 않은 경우에 주로 유용합니다 -f file1.
앤더스 요한슨

1
"comm"명령을 공유해 주셔서 감사합니다 @AndersJohansson. 정말 멋지다. 파일간에 외부 조인을 수행해야하는 경우가 많습니다.
blispr

줄 바꿈 문자에주의하십시오 ... 방금 \n비교를 위해 포함 될 것입니다.
Bin


28

diff리눅스에서 도구를 사용 하여 두 파일을 비교할 수 있습니다. --changed-group-format--unchanged-group-format을 사용할 수 있습니다 필터에 필요한 데이터에 대한 옵션을.

다음 세 가지 옵션을 사용하여 각 옵션에 대한 관련 그룹을 선택할 수 있습니다.

  • '% <'은 (는) FILE1에서 줄을 가져옵니다.

  • '%>'는 FILE2에서 줄을 가져옵니다.

  • 두 파일에서 줄을 제거하기위한 ''(빈 문자열)

예 : diff --changed-group-format = "% <"--unchanged-group-format = ""file1.txt file2.txt

[root@vmoracle11 tmp]# cat file1.txt 
test one
test two
test three
test four
test eight
[root@vmoracle11 tmp]# cat file2.txt 
test one
test three
test nine
[root@vmoracle11 tmp]# diff --changed-group-format='%<' --unchanged-group-format='' file1.txt file2.txt 
test two
test four
test eight

27

의 diff 출력 스타일을 선호하는 경우 git 저장소에없는 파일을 비교하기 git diff위해 --no-index플래그 와 함께 사용할 수 있습니다 .

git diff --no-index a.txt b.txt

각각 약 200k 개의 파일 이름 문자열을 가진 두 개의 파일을 사용하여 (내장 time명령으로)이 접근법을 벤치 마크 한 다른 답변과 비교했습니다.

git diff --no-index a.txt b.txt
# ~1.2s

comm -23 <(sort a.txt) <(sort b.txt)
# ~0.2s

diff a.txt b.txt
# ~2.6s

sdiff a.txt b.txt
# ~2.7s

vimdiff a.txt b.txt
# ~3.2s

comm반면, 훨씬 빠른 것 같다 git diff --no-index나타납니다이 사랑하는 스타일의 출력을위한 가장 빠른 방법이 될 수 있습니다.


2018-03-25 업데이트--no-index git 저장소 안에 있고 해당 저장소 내에서 추적되지 않은 파일을 비교하지 않는 한 실제로 플래그를 생략 할 수 있습니다 . 에서 맨 페이지 :

이 형식은 파일 시스템에서 주어진 두 경로를 비교하는 것입니다. Git으로 제어되는 작업 트리에서 명령을 실행하고 경로 중 하나 이상이 작업 트리 외부를 가리 키거나 Git에서 제어하는 ​​작업 트리 외부에서 명령을 실행할 때 --no-index 옵션을 생략 할 수 있습니다.




4

사용 comm -13 (정렬 된 파일 필요) :

$ cat file1
one
two
three

$ cat file2
one
two
three
four

$ comm -13 <(sort file1) <(sort file2)
four

1

여기 내 해결책이 있습니다.

mkdir temp
mkdir results
cp /usr/share/dict/american-english ~/temp/american-english-dictionary
cp /usr/share/dict/british-english ~/temp/british-english-dictionary
cat ~/temp/american-english-dictionary | wc -l > ~/results/count-american-english-dictionary
cat ~/temp/british-english-dictionary | wc -l > ~/results/count-british-english-dictionary
grep -Fxf ~/temp/american-english-dictionary ~/temp/british-english-dictionary > ~/results/common-english
grep -Fxvf ~/results/common-english ~/temp/american-english-dictionary > ~/results/unique-american-english
grep -Fxvf ~/results/common-english ~/temp/british-english-dictionary > ~/results/unique-british-english

2
다른 해결책을 시도 했습니까? 이 솔루션 중 하나가 도움이 되었습니까? 귀하의 질문은 많은 사용자에게 도움이 될 정도로 일반적이지만 귀하의 답변은 내 취향에 따라 더 구체적입니다 ... 내 특별한 경우 sdiff -s file1 file2에 유용했습니다.
Metafaniel

@ Metafaniel 내 솔루션은 sdiff 명령을 사용하지 않습니다. 문제를 해결하기 위해 Linux 내장 명령 만 사용합니다.
Ali Imran

-1

그것을 위해 awk를 사용합니다. 테스트 파일 :

$ cat a.txt
one
two
three
four
four
$ cat b.txt
three
two
one

awk :

$ awk '
NR==FNR {                    # process b.txt  or the first file
    seen[$0]                 # hash words to hash seen
    next                     # next word in b.txt
}                            # process a.txt  or all files after the first
!($0 in seen)' b.txt a.txt   # if word is not hashed to seen, output it

복제물이 출력됩니다.

four
four

중복을 피하려면 a.txt에서 새로 만난 각 단어를 seen해시에 추가하십시오.

$ awk '
NR==FNR {
    seen[$0]
    next
}
!($0 in seen) {              # if word is not hashed to seen
    seen[$0]                 # hash unseen a.txt words to seen to avoid duplicates 
    print                    # and output it
}' b.txt a.txt

산출:

four

단어 목록이 쉼표로 구분되어 있으면 다음과 같습니다.

$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three

여분의 랩 ( for루프)을 몇 번해야합니다 .

awk -F, '                    # comma-separated input
NR==FNR {
    for(i=1;i<=NF;i++)       # loop all comma-separated fields
        seen[$i]
    next
}
{
    for(i=1;i<=NF;i++)
        if(!($i in seen)) {
             seen[$i]        # this time we buffer output (below):
             buffer=buffer (buffer==""?"":",") $i
        }
    if(buffer!="") {         # output unempty buffers after each record in a.txt
        print buffer
        buffer=""
    }
}' b.txt a.txt

이번에 출력 :

four
five,six
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.