두 개의 텍스트 파일을 검색하고 그 중 하나에만 있는 각 파일의 줄을 파일로 인쇄하고 싶습니다.
예를 들어 LIST-1.txt에는 다음이 포함됩니다.
apples
dogs
paintings
mom
dad
don
LIST-2.txt에는 다음이 포함됩니다.
apples
don
dad
mom
cats
나는 출력을 (어떤 순서로든) 원한다:
dogs
paintings
cats
나는 이것을 시도했습니다 :
cat list-1.txt | while read line || [[ -n $line ]];
do
grep -v $line list-2.txt
done
어떤 제안이 있으십니까?
답변1
루프의 문제점은 각 반복마다 다음을 얻는다는 것입니다.첫 번째 파일의 현재 줄과 다른 두 번째 파일의 모든 줄.
루프의 변형은 다음 두 명령의 출력을 연결하는 것입니다.
grep -v -xF -f LIST-1.txt LIST-2.txt
grep -v -xF -f LIST-2.txt LIST-1.txt
첫 번째는 의 어떤 줄과 정확히 일치하지 않는 모든 줄을 grep
가져오는 반면, 두 번째는 두 파일에 대해 동일한 작업을 수행합니다. 이것은 실제로 귀하의 질문에 언급된 결과를 제공할 것입니다. (나는 보았다LIST-2.txt
LIST-1.txt
grep
Jeff는 이미 이것을 언급했습니다., 따라서 이 접근 방식이 마음에 든다면 내 답변 대신 그의 답변에 투표해 주세요. )
파일 중 하나를 쿼리 문자열로 메모리로 읽어야 하며 약간 우아하지 않은 것으로 간주될 수 있습니다. 또한 올바른 결과를 제공하지 못할 수 있는 상황에 대해서도 실제로 생각해 본 적이 없습니다.
개인적으로 저는 선택하겠습니다.
$ join -v 1 -v 2 <( sort LIST-1.txt ) <( sort LIST-2.txt )
cats
dogs
paintings
그러면 파일 간의 관계형 JOIN 작업이 수행됩니다. 일반적으로 이는 두 파일 모두에 존재하는 항목을 반환하지만(내부 조인) 여기서는 -v 1 -v 2
모든 항목을 확인 하도록 요청합니다.아니요모든 파일에서 일치합니다.
이 join
유틸리티에는 정렬된 입력이 필요합니다(한 번에 각 파일의 한 줄만 메모리에 보관할 수 있음). 따라서 두 파일을 모두 정렬하고 join
별도의 프로세스 교체를 통해 제공합니다.
프로세스 대체가 없는 셸에서는 다음을 호출하기 전에 파일의 정렬된 복사본을 만들어야 할 수도 있습니다 join
.
sort -o LIST-1.txt.sorted LIST-1.txt &&
sort -o LIST-2.txt.sorted LIST-2.txt &&
join -v 1 -v 2 LIST-[12].txt.sorted
rm -f LIST-[12].txt.sorted
답변2
방금 언급되었지만 명시적으로 설명되지 않았기 때문에: GNU comm
솔루션
comm --output-delimiter '' -3 <(sort file1) <(sort file2)
-3
두 파일 모두에 나타나는 줄을 억제하고 구분 기호 사양은 결과를 왼쪽 맞춤으로만 표시합니다. 그러나 제대로 작동하려면 파일을 정렬해야 합니다 comm
.
답변3
만약에재정렬된 결과는 신경 쓰지 않습니다. 한 가지 접근 방식은 다음과 같습니다.
sort
두 파일을 함께 넣어보세요uniq
인접한 중복 수를 계산하는 데 필요합니다 .awk
반복되지 않는 줄만 인쇄하도록 요청cut
삭제 요청uniq
개수
sort list-1.txt list-2.txt | uniq -c | awk '$1 == 1 { print}' | cut -c9-
grep이 이를 수행하도록 하려면 전체 줄, 고정 텍스트, 파일 기반 제외를 양방향으로 실행할 수 있습니다.
{ grep -vxF -f list-1.txt list-2.txt; grep -vxF -f list-2.txt list-1.txt; }
이를 위해서는 grep
첫 번째 파일에 없는 두 번째 파일의 줄이 필요합니다. 여기서 두 번째 파일의 파일 이름을 바꿉니다 grep
.
답변4
입력 파일에 별도의 중복 항목이 없으면 다음을 사용할 수 있습니다.
sort list[12] |uniq -u
또는 awk
대안으로 사용:
awk '{ seen[$0]++ } END{ for (x in seen) if (seen[x]==1) print x }' list[12]