유닉스 파일에서 중복 줄을 삭제하는 방법이 있습니까?
sort -u
와 uniq
명령으로 할 수 있지만 sed
또는 을 사용하고 싶습니다 awk
. 가능합니까?
awk
하지만 더 큰 파일에서 리소스를 많이 소비 할 것이라고 생각 합니다.
유닉스 파일에서 중복 줄을 삭제하는 방법이 있습니까?
sort -u
와 uniq
명령으로 할 수 있지만 sed
또는 을 사용하고 싶습니다 awk
. 가능합니까?
awk
하지만 더 큰 파일에서 리소스를 많이 소비 할 것이라고 생각 합니다.
답변:
awk '!seen[$0]++' file.txt
seen
Awk가 파일의 모든 줄을 전달할 연관 배열입니다. 행이 배열에 없으면 seen[$0]
false로 평가됩니다. 는 !
논리적 NOT 연산자 true로 거짓을 반전합니다. Awk는 표현식이 true로 평가되는 행을 인쇄합니다. ++
증가 seen
되도록 seen[$0] == 1
제 시간 후에 라인하고 발견 seen[$0] == 2
등.
Awk는 0
및 ""
(빈 문자열)을 제외한 모든 것을 평가 합니다. 중복 라인에 배치되어있는 경우 seen
다음 !seen[$0]
false로 평가되고 라인은 출력에 기록되지 않습니다.
awk '!seen[$0]++' merge_all.txt > output.txt
for f in *.txt; do gawk -i inplace '!seen[$0]++' "$f"; done
에서 http://sed.sourceforge.net/sed1line.txt : (어떻게이 일을 부탁하지 마십시오 ;-))
# delete duplicate, consecutive lines from a file (emulates "uniq").
# First line in a set of duplicate lines is kept, rest are deleted.
sed '$!N; /^\(.*\)\n\1$/!P; D'
# delete duplicate, nonconsecutive lines from a file. Beware not to
# overflow the buffer size of the hold space, or else use GNU sed.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
$!
부분은 필요? 하지 않습니다 sed 'N; /^\(.*\)\n\1$/!P; D'
같은 일을? 나는 내 컴퓨터에서 두 가지가 다른 예를 생각해 낼 수 없습니다 (fwiw 두 가지 버전으로 끝에 빈 줄을 시도했지만 모두 괜찮 았습니다).
@jonas의 awk 솔루션과 비슷한 Perl one-liner :
perl -ne 'print if ! $x{$_}++' file
이 변형은 다음을 비교하기 전에 후행 공백을 제거합니다.
perl -lne 's/\s*$//; print if ! $x{$_}++' file
이 변형은 파일을 내부 편집합니다.
perl -i -ne 'print if ! $x{$_}++' file
이 변형은 파일을 내부 편집하고 백업합니다 file.bak
perl -i.bak -ne 'print if ! $x{$_}++' file
Andre Miller가 위에 게시 한 라이너는 입력 파일이 빈 줄로 끝나고 문자가없는 경우 최신 버전의 sed를 제외하고 작동합니다. 내 Mac에서 CPU가 회전합니다.
마지막 줄이 비어 있고 문자가없는 경우 무한 루프 :
sed '$!N; /^\(.*\)\n\1$/!P; D'
멈추지 않지만 마지막 줄을 잃습니다.
sed '$d;N; /^\(.*\)\n\1$/!P; D'
설명은 sed FAQ 의 맨 끝에 있습니다 .
GNU sed 관리자는 이식성 문제에도 불구하고
N 명령을 변경 (
삭제 대신 인쇄)하도록 변경하면
"다음 줄 추가"명령 이 어떻게 동작 해야하는지 에 대한 직감과 패턴 공간이 더 일관성이 있다고 생각했습니다 .
변경을 선호하는 또 다른 사실
은 파일에 홀수가있는 경우 "{N; command;}"은 마지막 라인 을 삭제하지만 파일에 짝수 개의
라인이 있으면 마지막 라인을 인쇄한다는 것입니다.이전의 N 동작 (
EOF에 도달 할 때 패턴 공간 삭제 )을 사용한 스크립트를
모든 버전의 sed 와 호환 되는 스크립트로 변환하려면 고독한 "N;"을 변경하십시오. "$ d; N;" .
$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr '$!N;/^(.*)\n\1$/!P;D'
1
2
3
4
5
핵심 아이디어는 다음과 같습니다.
print ONLY once of each duplicate consecutive lines at its LAST appearance and use D command to implement LOOP.
설명합니다 :
$!N;
: 현재 행이 마지막 행이 아닌 경우 N
명령을 사용 하여 다음 행을로 읽어보십시오 pattern space
./^(.*)\n\1$/!P
: 전류의 내용 pattern space
이 두 개로 duplicate string
분리되어 \n
다음 줄이 same
현재 라인과 함께 있음을 의미하는 경우 핵심 아이디어에 따라 인쇄 할 수 없습니다. 그렇지 않으면, 현재 행이 모든 중복 된 연속 행의 마지막 모양임을 의미합니다. 이제 P
명령을 사용 하여 현재 pattern space
util 에서 문자를 인쇄 할 수도 있습니다 \n
( \n
또한 인쇄 됨).D
: 우리는 D
command를 사용하여 현재 pattern space
util 에서 문자를 삭제하고 \n
( \n
삭제됨) 내용은 pattern space
다음 줄입니다.D
명령은 강제로 sed
그에게 이동 FIRST
명령 $!N
하지만, 파일 또는 표준 입력 스트림에서 다음 줄을 읽을 수 없습니다.$ echo -e '1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5' |sed -nr 'p;:loop;$!N;s/^(.*)\n\1$/\1/;tloop;D'
1
2
3
4
5
핵심 아이디어는 다음과 같습니다.
print ONLY once of each duplicate consecutive lines at its FIRST appearance and use : command & t command to implement LOOP.
설명합니다 :
:loop
명령 세트 label
의 이름 loop
.N
다음 줄을 읽는 데 사용 하십시오 pattern space
.s/^(.*)\n\1$/\1/
다음 행이 현재 행과 동일하면 현재 행을 삭제 하는 데 사용합니다. s
명령을 사용 하여 delete
작업 을 수행합니다 .s
명령이 성공적으로 실행 되면 tloop
command force sed
를 사용 하여 label
named loop
로 이동합니다. 그러면 다음 행과 동일한 루프를 수행합니다. util 행의 중복 된 연속 행은 없습니다 latest printed
. 그렇지 않으면, 사용 D
에 명령 delete
하여와 동일 라인 latest-printed line
, 그리고 힘 sed
은 IS 첫 번째 명령에 이동 p
명령, 현재의 내용은 pattern space
다음 새로운 라인입니다.busybox echo -e "1\n2\n2\n3\n3\n3\n4\n4\n4\n4\n5" | busybox sed -nr "$!N;/^(.*)\n\1$/!P;D"
cat filename | sort | uniq -c | awk -F" " '$1<2 {print $2}'
awk를 사용하여 중복 행을 삭제합니다.
cat
쓸모가 없다. 어쨌든 uniq
이미 자체적으로 수행하며 입력이 한 줄에 정확히 하나의 단어 일 필요는 없습니다.
uniq
혼자이면 충분합니다.