오늘 이 사용 사례를 발견했습니다. 언뜻 보면 간단해 보이지만, 가지고 놀아보면 sort
간단 하지 않다는 것을 알게 uniq
될 sed
것입니다 .awk
어떻게 모두 삭제할 수 있나요?오른쪽행이 중복되나요? 즉, 특정 행에 대해 짝수 개의 중복 행이 있으면 모두 삭제하고, 홀수 개의 중복 행이 있으면 한 행만 남기고 모두 삭제합니다. (정렬된 입력을 가정할 수 있습니다.)
깨끗하고 우아한 솔루션이 더 나은 선택입니다.
입력 예:
a
a
a
b
b
c
c
c
c
d
d
d
d
d
e
출력 예:
a
d
e
답변1
sed
이 질문을 게시한 직후에 답변을 찾았습니다. sed
지금까지 아무도 이 질문을 사용하지 않았으므로 다음과 같습니다.
sed '$!N;/^\(.*\)\n\1$/d;P;D'
보다 일반적인 문제(3개, 4개 또는 5개 행을 삭제하는 것은 어떻습니까?)에 대한 좀 더 일반적인 솔루션은 다음과 같은 확장 가능한 솔루션을 제공합니다.
sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
확장하여 세 개의 행을 제거합니다.
sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
또는 쿼드 라인을 삭제합니다.
sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp
sed
스트림에서 실제로 작동할 수 있다는 점에서 대부분의 다른 옵션에 비해 추가적인 이점이 있으며, 중복 여부를 확인할 실제 행 수보다 더 많은 메모리 저장 공간이 필요하지 않습니다.
~처럼cuonglm이 댓글에서 지적했어요, 멀티바이트 문자가 포함된 줄이 잘못 삭제되는 것을 방지하려면 로케일을 C로 설정해야 합니다. 따라서 위 명령은 다음과 같습니다.
LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.
답변2
매우 우아하지는 않지만 제가 생각할 수 있는 가장 간단한 방법은 다음과 같습니다.
uniq -c input | awk '{if ($1 % 2 == 1) { print substr($0, 9) }}'
substr()은 출력을 다듬습니다 uniq
. 이는 한 줄의 반복 횟수가 9,999,999를 초과할 때까지 작동합니다(이 경우 uniq의 출력은 9자로 오버플로될 수 있습니다).
답변3
awk
다음 스크립트를 시도해 보세요 .
#!/usr/bin/awk -f
{
if ((NR!=1) && (previous!=$0) && (count%2==1)) {
print previous;
count=0;
}
previous=$0;
count++;
}
END {
if (count%2==1) {
print previous;
}
}
lines.txt
파일이 정렬되었다고 가정합니다 .
시험을 치르다:
$ chmod +x script.awk
$ ./script.awk lines.txt
a
d
e
답변4
입력이 정렬된 경우:
perl -0pe 'while(s/^(.*)\n\1\n//m){}'