두 개의 목록이 있습니다.
더 큰 "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"인 경우 제외되지 않습니다.
- 가능한 해시 삽입 외에는 정렬이 수행되지 않으므로 처리되는 파일은 원하는 크기나 데이터 스트림 등이 될 수 있습니다.
- 입력 파일 이름을 전달하거나 제외 스위치 뒤에 입력을 파이프하십시오.