한 번 이상 두 개 이상의 파일에서 공통 줄을 인쇄 할 수있는 유닉스 명령을 찾았습니다. 누가 그 이름을 알고 있습니까? 보다 훨씬 간단했다 diff
.
pr-123-xy-45
있고 file2에 포함되는 경우 두 파일간에 공통되는 방법이 있습니다 ec11_orop_pr-123-xy-45.gz
. 다음을 포함하는 file3이 필요합니다ec11_orop_pr-123-xy-45.gz
한 번 이상 두 개 이상의 파일에서 공통 줄을 인쇄 할 수있는 유닉스 명령을 찾았습니다. 누가 그 이름을 알고 있습니까? 보다 훨씬 간단했다 diff
.
pr-123-xy-45
있고 file2에 포함되는 경우 두 파일간에 공통되는 방법이 있습니다 ec11_orop_pr-123-xy-45.gz
. 다음을 포함하는 file3이 필요합니다ec11_orop_pr-123-xy-45.gz
답변:
당신이 찾고있는 명령은 comm
입니다. 예 :-
comm -12 1.sorted.txt 2.sorted.txt
여기:
-1 : 열 1을 숨 깁니다 (1.sorted.txt에 고유 한 행)
-2 : 열 2 억제 (2.sorted.txt에 고유 한 행)
grep
예상치 못한 이상한 일을합니다. 구체적으로 모든 내용은 1.txt
일반 문자열이 아닌 정규식으로 해석됩니다. 또한 빈 줄은의 1.txt
모든 줄과 일치합니다 2.txt
. 그래서 grep
매우 구체적인 상황에서 작동합니다. 적어도 fgrep
(또는 grep -f
) 를 사용하고 싶지만 빈 줄이 아마도이 과정을 혼란스럽게 할 것입니다.
comm
을 3 개의 별도 파일로 가져 오는 방법으로 자체 답변 Q & A를 제공 했습니까? 대답이 너무 커서 여기에 편안하게 들어갈 수 없었습니다.
정렬되지 않은 파일에 comm 명령 을 쉽게 적용하려면 Bash의 프로세스 대체를 사용하십시오 .
$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321
따라서 abc 및 def 파일에는 공통으로 한 줄이 있고 "132"줄이 있습니다. 정렬되지 않은 파일에서 통신 사용 :
$ comm abc def
123
132
567
132
777
321
$ comm -12 abc def # No output! The common line is not found
$
마지막 라인은 출력을 생성하지 않았으며 공통 라인은 발견되지 않았습니다.
이제 정렬 된 파일에 comm 을 사용 하여 파일을 프로세스 대체로 정렬하십시오.
$ comm <( sort abc ) <( sort def )
123
132
321
567
777
$ comm -12 <( sort abc ) <( sort def )
132
이제 우리는 132 라인을 얻었습니다!
sort abc > abc.sorted
, sort dev > def.sorted
다음 comm -12 abc.sorted def.sorted
?
Perl 원 라이너를 보완하기 위해 다음 awk
과 같습니다.
awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2
그러면 모든 줄을 file1
배열로 읽어 들인 arr[]
다음 각 줄 file2
이 이미 배열 내에 있는지 확인합니다 (예 :) file1
. 찾은 줄은에 나타난 순서대로 인쇄됩니다 file2
. 비교 in arr
는 file2
색인에서 배열 까지의 전체 행을 사용하므로 전체 행에서 정확히 일치하는 항목 만보고합니다.
perl
않았기 때문에). 고마워요, Ms.
아마 당신은 의미 comm
합니까?
정렬 된 파일 FILE1과 FILE2를 한 줄씩 비교하십시오.
옵션이 없으면 3 열 출력을 생성합니다. 열 1에는 FILE1에 고유 한 행이 있고 열 2에는 FILE2에 고유 한 행이 있고 열 3에는 두 파일에 공통 인 행이 있습니다.
이러한 정보를 찾는 비결은 정보 페이지입니다. GNU 프로그램의 경우, 맨 페이지보다 훨씬 상세합니다. 시도해 info coreutils
보면 작은 유용한 유틸리티가 모두 나열됩니다.
동안
grep -v -f 1.txt 2.txt > 3.txt
두 파일의 차이점을 제공합니다 (1.txt가 아닌 2.txt에 있음).
grep -f 1.txt 2.txt > 3.txt
모든 공통 라인을 수집하여 문제점에 대한 쉬운 솔루션을 제공해야합니다. 파일을 정렬 한 경우에도 가져 가야 comm
합니다. 문안 인사!
grep
예상치 못한 이상한 일을합니다. 구체적으로 모든 내용은 1.txt
일반 문자열이 아닌 정규식으로 해석됩니다. 또한 빈 줄은의 1.txt
모든 줄과 일치합니다 2.txt
. 따라서 이것은 매우 구체적인 상황에서만 작동합니다.
grep
표기법을 사용하여 더 잘 작동하도록이 답변을 업그레이드 할 수 있습니다. POSIX 표기법 grep
은 대부분의 최신 Unix 변형에서 지원됩니다 . 정규식을 억제 -F
하려면을 추가 하거나 사용 하십시오 fgrep
. -x
전체 줄에만 일치하도록 (정확히) 추가하십시오 .
comm
정렬 된 파일을 사용해야하는 이유는 무엇 입니까?
comm
은 메모리에 3 줄만 있으면되기 때문에 정렬 된 한 임의로 큰 파일을 사용할 수 있습니다 (GNU comm
가 줄이 실제로 길면 접두사를 유지하는 것으로 알고 있습니다). grep
솔루션은 메모리에 모든 검색 식을 유지해야합니다.
두 파일이 아직 정렬되지 않은 경우 다음을 사용할 수 있습니다.
comm -12 <(sort a.txt) <(sort b.txt)
comm: file 2 is not in sorted order
할 때 오류 메시지를 피하면서 작동 comm -12 a.txt b.txt
합니다.
<(command)
은 Bash 및 기타에서 작동하지만 POSIX 셸로 이식 할 수 없습니다.
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
comm
그것의 각 라인 검색으로 명령 file1
에 file2
어디에 comm
줄 경우에만 비교합니다 n
에서 file1
IS 라인에 동일 n
의를 file2
.
comm
단순히 file1의 N 행을 file2의 N 행과 비교하지는 않습니다. 파일에 삽입 된 일련의 라인을 완벽하게 관리 할 수 있습니다 (물론 다른 파일에서 일련의 라인을 삭제하는 것과 같습니다). 입력이 정렬 순서대로되어 있으면됩니다.
comm
주문을 유지하려면 답변 보다 낫습니다 . awk
중복을 원하지 않으면 대답 보다 낫습니다 .
Linux의 제한된 버전 (QNAP (nas)와 같은)은 다음과 같습니다.
grep -f file1 file2
@ChristopherSchultz가 말한 것처럼 일부 문제가 발생할 수 있으며 사용 grep -F -f file1 file2
이 실제로 느려졌습니다 (5 분 이상-완료되지 않음-아래 방법으로 20MB가 넘는 파일에서 2-3 초 이상)그래서 여기 내가 한 일이 있습니다.
sort file1 > file1.sorted
sort file2 > file2.sorted
diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted
files.same.sorted
원래의 순서와 동일한 순서로되어 있다면 file1과 동일한 순서로이 행을 추가하십시오.
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same
또는 file2와 동일한 순서로 :
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same
누군가가 여러 파일에 대해이 작업을 수행하는 방법을 계속 찾고 있다면 많은 파일에서 일치하는 줄 찾기에 대한 링크 된 답변을 참조하십시오 .
이 두 가지 답변 ( ans1 과 ans2 )을 결합 하면 파일을 정렬하지 않고도 필요한 결과를 얻을 수 있다고 생각합니다.
#!/bin/bash
ans="matching_lines"
for file1 in *
do
for file2 in *
do
if [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
echo "Comparing: $file1 $file2 ..." >> $ans
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
fi
done
done
간단히 저장하고 실행 권한을 부여하고 ( chmod +x compareFiles.sh
) 실행하십시오. 현재 작업 디렉토리에있는 모든 파일을 가져 와서 "matching_lines"파일에 결과를 남겨두고 모든 비교를 수행합니다.
개선 사항 :
rm file3.txt
cat file1.out | while read line1
do
cat file2.out | while read line2
do
if [[ $line1 == $line2 ]]; then
echo $line1 >>file3.out
fi
done
done
그렇게해야합니다.
rm -f file3.txt
파일을 삭제하려는 경우 사용해야 합니다. 파일이 존재하지 않으면 오류가보고되지 않습니다. OTOH, 스크립트가 단순히 표준 출력으로 에코되어 스크립트 사용자가 출력 위치를 선택할 수 있도록하는 경우 필요하지 않습니다. 궁극적 으로 고정 파일 이름 ( 및 ) 대신 $1
및 $2
(명령 줄 인수) 를 사용하려고합니다 . 그것은 알고리즘을 떠난다 : 그것은 느려질 것이다. 의 각 줄에 대해 한 번씩 읽 습니다 . 파일이 큰 경우 (예 : 여러 킬로바이트) 속도가 느려집니다. file1.out
file2.out
file2.out
file1.out
grep -F
하나의 파일을 메모리로 읽은 다음 다른 파일을 한 번만 통과 하는 도구는 두 입력 파일 모두에서 반복적으로 반복되는 것을 피합니다.
comm
정렬 된 입력 파일이 필요하므로이 질문에 대한 답변이 모든 사람이 원하는 것은 아닙니다 . 라인 단위 공통을 원한다면 훌륭합니다. 그러나 당신이 "anti-diff"라고 부르는 것을 원한다면comm
그 일을하지 마십시오.