[linux] 다른 파일 A에서 파일 B에 나타나는 줄을 제거하는 방법?
메일마다 한 줄씩 큰 파일 A (이메일로 구성)가 있습니다. 또한 다른 메일 세트를 포함하는 다른 파일 B 가 있습니다.
파일 A에서 파일 B에 나타나는 모든 주소를 제거하기 위해 어떤 명령을 사용합니까?
따라서 파일 A에 포함 된 경우 :
A
B
C
파일 B에는 다음이 포함됩니다.
B
D
E
그런 다음 파일 A는 다음과 같이 남겨 두어야합니다.
A
C
이제 이것이 더 자주 묻는 질문이라는 것을 알고 있지만 온라인 에서 하나의 명령 만 발견 하여 잘못된 구분 기호가있는 오류를 발견했습니다.
어떤 도움이라도 대단히 감사하겠습니다! 누군가는 분명히 영리한 원 라이너를 내놓을 것이지만 저는 쉘 전문가가 아닙니다.
답변
파일이 정렬 된 경우 (예 : 파일에 있음) :
comm -23 file1 file2
-23
두 파일 모두 또는 파일 2에만있는 행을 표시하지 않습니다. 파일이 정렬되지 않은 경우 먼저 파일을 통해 파이프하십시오 sort
.
참고 항목 여기 사람이 페이지를
답변
grep -Fvxf <lines-to-remove> <all-lines>
- 분류되지 않은 파일에서 작동
- 순서를 유지
- POSIX입니다
예:
cat <<EOF > A
b
1
a
0
01
b
1
EOF
cat <<EOF > B
0
1
EOF
grep -Fvxf B A
산출:
b
a
01
b
설명:
-F
: 기본 BRE 대신 리터럴 문자열을 사용하십시오.-x
: 전체 줄과 일치하는 항목 만 고려-v
: 일치하지 않는 인쇄-f file
: 주어진 파일에서 패턴을 가져옵니다
이 방법은 다른 방법보다 미리 정렬 된 파일에서 속도가 느립니다. 더 일반적이기 때문입니다. 속도도 중요하다면, 한 파일에서 다른 파일에없는 행을 찾는 빠른 방법을 참조하십시오.
인라인 작업을위한 빠른 bash 자동화는 다음과 같습니다.
remove-lines() (
remove_lines="$1"
all_lines="$2"
tmp_file="$(mktemp)"
grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file"
mv "$tmp_file" "$all_lines"
)
용법:
remove-lines lines-to-remove remove-from-this-file
참조 : /unix/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another
답변
구조에 awk!
이 솔루션에는 정렬 된 입력이 필요하지 않습니다. 먼저 fileB를 제공해야합니다.
awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA
보고
A
C
어떻게 작동합니까?
NR==FNR{a[$0];next}
관용구는 첫 번째 파일을 나중에 “포함하는”테스트를 위해 키로 연관 배열에 저장하기위한 것입니다.
NR==FNR
전역 라인 카운터 (NR)가 현재 파일 라인 카운터 (FNR)와 동일한 첫 번째 파일을 스캔하고 있는지 확인합니다.
a[$0]
현재 행을 연관 배열에 키로 추가합니다. 이것은 중복 값 (키)이없는 집합처럼 동작합니다.
!($0 in a)
우리는 이제 다음 파일에in
있으며, 포함 테스트입니다. 여기서 현재 줄이 첫 번째 파일의 첫 번째 단계에서 채워진 세트에 있는지 확인!
하고 조건을 무시합니다. 여기서 누락 된 작업은 기본적{print}
으로 명시 적으로 작성되지 않은 작업입니다.
블랙리스트에 포함 된 단어를 제거하는 데 사용할 수 있습니다.
$ awk '...' badwords allwords > goodwords
약간의 변경으로 여러 목록을 정리하고 정리 된 버전을 만들 수 있습니다.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
답변
동일한 작업을 수행하는 다른 방법 (정렬 된 입력도 필요함) :
join -v 1 fileA fileB
Bash에서 파일이 미리 정렬되지 않은 경우 :
join -v 1 <(sort fileA) <(sort fileB)
답변
파일이 정렬되어 있지 않으면이 작업을 수행 할 수 있습니다
diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a
--new-line-format
파일 b에 있지만 a --old-..
가 아닌
행은 파일 a에 있지만 b --unchanged-..
는 아닌
행은 둘 다에있는 행입니다.
%L
선이 정확하게 인쇄되도록합니다.
man diff
상세 사항은
답변
@karakfa의 멋진 대답의 미세 조정은 매우 큰 파일의 경우 훨씬 빠릅니다. 이 답변과 마찬가지로 파일을 정렬 할 필요는 없지만 awk의 연관 배열 덕분에 속도가 보장됩니다. 조회 파일 만 메모리에 보관됩니다.
이 공식은 또한 입력 파일에서 하나의 특정 필드 ($ N) 만 비교에 사용될 가능성을 허용합니다.
# Print lines in the input unless the value in column $N
# appears in a lookup file, $LOOKUP;
# if $N is 0, then the entire line is used for comparison.
awk -v N=$N -v lookup="$LOOKUP" '
BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } }
!($N in dictionary) {print}'
(이 방법의 또 다른 장점은 선행 및 후행 공백을 트리밍하는 등 비교 기준을 쉽게 수정할 수 있다는 것입니다.)
답변
파이썬을 사용할 수 있습니다 :
python -c '
lines_to_remove = set()
with open("file B", "r") as f:
for line in f.readlines():
lines_to_remove.add(line.strip())
with open("file A", "r") as f:
for line in [line.strip() for line in f.readlines()]:
if line not in lines_to_remove:
print(line)
'