"A"의 모든 요소를 ​​포함하지만 "B"의 요소는 전혀 포함하지 않는 목록 "C"가 필요합니다.

"A"의 모든 요소를 ​​포함하지만 "B"의 요소는 전혀 포함하지 않는 목록 "C"가 필요합니다.

두 개의 목록이 있습니다.

더 큰 "A":

A=`echo -e '1\n2\n3\n4\n5'`
echo "$A"
1
2
3
4
5

더 작은 "B":

B=`echo -e '1\n2\n3'`
echo "$B"
1
2
3

묻다:하지만 "A"의 모든 요소를 ​​포함하지만 "B"는 포함하지 않는 세 번째 목록이 필요합니다. bash에서 이를 어떻게 수행할 수 있습니까?

echo "$C"
4
5

숫자는 "foo"부터 99까지 가능합니다.

고쳐 쓰다:

쉘에서는 수동으로 작동하는데, 스크립트에 넣으면 작동하지 않아서 이상해요!

cat a.txt 
A=$(seq 5)
B=$(seq 3)
comm -23 <(sort <<< "$A") <(sort <<< "$B")
sh a.txt 
a.txt: line 3: syntax error near unexpected token `('
a.txt: line 3: `comm -23 <(sort <<< "$A") <(sort <<< "$B")'

수제 작동합니다 ..:

A=$(seq 5)
B=$(seq 3)
comm -23 <(sort <<< "$A") <(sort <<< "$B")
4
5

왜?업데이트 업데이트: "sh" 대신 bash를 사용해야 합니다. :D

답변1

이것comm필요한 명령은 다음과 같습니다.

$ A=$(seq 5)
$ B=$(seq 3)
$ comm -23 <(sort <<< "$A") <(sort <<< "$B")
4
5

이는 입력을 정렬할 필요가 없는 방법입니다. 이는 첫 번째 파일을 메모리로 읽은 다음 첫 번째 파일을 기반으로 두 번째 파일을 필터링하는 awk의 일반적인 관용어입니다. 무작위 데이터를 사용해 봅시다

$ A=$(seq 5 | sort -R); echo "$A"
3
5
1
2
4
$ B=$(seq 3 | sort -R); echo "$B"
2
1
3

출력은 처음에는 5, 그다음에는 4가 될 것으로 예상됩니다.

$ awk 'NR==FNR {b[$1]=1; next} !($1 in b) {print}' <(echo "$B") <(echo "$A")
5
4

답변2

Glenn Jackman이 제공한 대로 이 comm유틸리티는 이를 수행하는 가장 쉬운 방법입니다. 그러나 이 방법은 정렬 순서를 파괴합니다.

이를 달성하는 또 다른 방법은 원래 정렬 순서를 유지하는 것입니다(두 목록 모두 동일한 순서로 미리 정렬되어야 함).

diff --unchanged-line-format '' --old-line-format '' file_a file_b

file_b그러면 원래 순서대로 고유한 모든 행이 반환됩니다.
 

데이터 세트가 매우 크다면 이것이 더 효율적일 것이라고 믿습니다. 정렬 작업에는 비용이 많이 들 수 있기 때문입니다. 그러나 이것은 단지 추측일 뿐이다.

답변3

sort a b b | uniq -u

Hills(UNIX 7)보다 오래되었지만 여전히 유효합니다.

답변4

또는 Perl은 다음과 같습니다.

#!/usr/bin/perl -s
if($#ARGS == 0) {print "Usage: $0 -exclude=fileWithLinesToExclude [inputFile]\n"; exit(0)}
open(EXCL, $exclude);
%excluded = map { $_ => 1 } <EXCL>;
while(<>) {
   print $_ unless $excluded{$_};
} 

물건

  • perl -s스위치가 변수 값이 되도록 허용
  • 씹는 일이 발생하지 않으며 제외된 행이 "foobar_"이고 처리된 행이 "foobar"인 경우 제외되지 않습니다.
  • 가능한 해시 삽입 외에는 정렬이 수행되지 않으므로 처리되는 파일은 원하는 크기나 데이터 스트림 등이 될 수 있습니다.
  • 입력 파일 이름을 전달하거나 제외 스위치 뒤에 입력을 파이프하십시오.

관련 정보