유닉스 파일에서 중복 줄을 삭제하는 방법이 있습니까?
sort -u
와 uniq
명령으로 할 수 있지만 sed
또는 을 사용하고 싶습니다 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로 평가되고 라인은 출력에 기록되지 않습니다.
답변
에서 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'
답변
@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;” .
답변
Vim (Vi 호환)을 사용하는 다른 방법 :
파일에서 연속 된 중복 행을 삭제합니다.
vim -esu NONE +'g/\v^(.*)\n\1$/d' +wq
파일에서 연속적이며 비 연속적인 행을 삭제합니다.
vim -esu NONE +'g/\v^(.+)$\_.{-}^\1$/d' +wq
답변
첫 번째 해결책은 또한 http://sed.sourceforge.net/sed1line.txt입니다.
$ 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 forcesed
를 사용 하여label
namedloop
로 이동합니다. 그러면 다음 행과 동일한 루프를 수행합니다. util 행의 중복 된 연속 행은 없습니다latest printed
. 그렇지 않으면, 사용D
에 명령delete
하여와 동일 라인latest-printed line
, 그리고 힘sed
은 IS 첫 번째 명령에 이동p
명령, 현재의 내용은pattern space
다음 새로운 라인입니다.
답변
아래 awk를 사용하여 달성 할 수 있습니다.
awk file_name | uniq
이 고유 한 값을 새 파일로 출력 할 수 있습니다
awk file_name | uniq > uniq_file_name
새 파일 uniq_file_name에는 고유 값만 포함되며 중복은 없습니다.