빌드노트
sort -nu를 넣었더니 서로 다른 로그 줄이 사라진다
GNU sort -nu는 숫자 키가 같은 줄을 하나로 줄인다. 네 줄 실험으로 sort -n | uniq와 비교하고, 명시적 키와 -s가 전체 줄 중복 제거에 미치는 차이를 확인한다.
숫자로 시작하는 로그를 정렬하면서 중복을 지우려고 GNU sort -nu를 붙였는데, 10 alpha와 10 beta 중 한 줄만 남을 수 있다. -u가 숫자 비교에서 같은 값인 줄을 하나로 줄이기 때문이다. 메시지가 다른 줄을 보존하고 완전히 같은 줄만 지우려면 sort -n의 출력을 별도 uniq에 넘긴다.
아래는 실제 로그를 가공한 기록이 아니라 네 줄의 합성 입력으로 재현한 결과다. WSL2의 Ubuntu 24.04.4 LTS에서 GNU coreutils 9.4의 sort와 uniq, Bash 5.2.21로 실행했다. Linux 또는 WSL의 Bash에서 따라 할 수 있으며, PowerShell의 sort와 혼동하지 않도록 해당 셸에서 sort --version으로 GNU 구현인지 확인한다.
숫자 10이 같으면 메시지도 같은 것으로 줄어든다
빈 실습 폴더에서 다음 명령으로 events.txt를 새로 만든다. 첫 번째와 마지막 줄만 정확히 같고, 10 beta는 별개의 줄이다.
printf '%s\n' '10 alpha' '10 beta' '2 gamma' '10 alpha' > ./events.txt
먼저 문제가 되는 명령을 같은 입력에 실행한다. LC_ALL=C는 각 명령의 비교 환경만 고정하며 시스템 설정을 바꾸지 않는다.
LC_ALL=C sort -nu ./events.txt
실제 출력은 두 줄이었다.
2 gamma
10 alpha
10 alpha의 정확 중복뿐 아니라 10 beta도 없어졌다. 여기서 -n은 줄 앞의 숫자를 비교하므로 세 줄의 값이 모두 10이다. -u는 그 비교에서 같다고 판정한 줄 가운데 하나만 출력한다. -n과 -u를 함께 썼을 때는 뒤의 문자열이 다르다는 이유로 두 줄을 구별하지 않는다. 실행 버전에 해당하는 GNU coreutils 9.4 공식 매뉴얼 원본의 sort 절 (새 탭에서 열림)도 sort -n -u와 sort -n | uniq의 차이를 이 비교 기준으로 설명한다.
이번 입력에서는 먼저 나온 10 alpha가 남았다. 숫자 10의 첫 줄을 10 beta로 바꾼 별도 비교에서는 10 beta가 남았다. 이 결과를 알파벳상 최소 메시지나 최신 로그를 고르는 규칙으로 해석하면 안 된다. 같은 숫자의 로그를 전부 읽어야 한다면 이 단계의 -u부터 제거한다. 이미 줄어든 출력에 uniq를 더해도 없어진 메시지는 복원되지 않는다.
완전히 같은 줄만 지우려면 비교를 한 번 더 한다
-u만 뺀 출력에서 어떤 줄이 보존되는지 먼저 확인한다.
LC_ALL=C sort -n ./events.txt
네 줄이 모두 남고, 같은 10 alpha 두 줄이 붙는다.
2 gamma
10 alpha
10 alpha
10 beta
GNU sort는 지정한 키의 비교가 같으면 마지막으로 전체 줄을 비교해 순서를 정한다. 그래서 이 조건에서는 10 alpha 두 줄을 붙일 수 있다. -u는 이 마지막 전체 줄 비교를 끄므로 앞의 두 줄짜리 결과와 달라진다. 같은 매뉴얼에 설명된 이 동작이 두 명령의 차이를 만든다.
이제 정렬 결과를 옵션 없는 uniq로 넘겨, 붙어 있는 같은 줄만 하나로 줄인다.
LC_ALL=C sort -n ./events.txt | LC_ALL=C uniq
이번에는 메시지가 다른 두 줄이 모두 남는다.
2 gamma
10 alpha
10 beta
숫자는 오름차순이고 정확 중복만 제거됐다. 파이프 양쪽에 LC_ALL=C를 붙인 것은 두 명령의 환경을 각각 지정하기 위해서다. 왼쪽 명령 앞의 환경변수 지정이 오른쪽 명령까지 자동으로 적용되는 것은 아니다.
uniq만 원본에 실행한 결과는 입력과 같은 네 줄이었다. 두 10 alpha가 떨어져 있기 때문이다. GNU coreutils 9.4 공식 매뉴얼 원본의 uniq 절 (새 탭에서 열림)에 설명된 것처럼, 기본 uniq는 인접한 반복만 제거한다. 따라서 이 해법에서는 정렬이 중복 줄을 붙여 주는 단계까지 맡는다.
키를 명시해도 -u의 중복 기준은 바뀌지 않는다
이 입력처럼 첫 필드가 숫자라면 -k1,1n으로 첫 필드만 숫자 키라고 명시할 수 있다. 시작 필드와 끝 필드를 모두 1로 지정하고 그 키에 숫자 비교 n을 붙인 표기다. 같은 파일에 아래 두 명령을 실행해 중복 기준을 비교한다.
LC_ALL=C sort -k1,1n -u ./events.txt
LC_ALL=C sort -k1,1n ./events.txt | LC_ALL=C uniq
첫 명령은 앞서 본 sort -nu와 같은 두 줄을, 둘째 명령은 세 줄을 출력했다. -k1,1n -u도 첫 필드가 10인 줄을 한 그룹으로 줄인다. 키를 명확히 지정하는 것과 전체 줄의 중복만 제거하는 것은 별개의 선택이다. 숫자 키마다 한 줄만 필요할 때는 첫 명령을, 메시지가 다르면 모두 남겨야 할 때는 둘째 명령을 선택한다.
-s를 추가하면 uniq가 지울 중복이 떨어질 수 있다
같은 숫자 안에서는 원본의 상대 순서를 유지하고 싶어 안정 정렬 옵션 -s를 추가할 수 있다. 그러면 전체 줄로 동률을 푸는 비교가 꺼진다. 같은 입력에서 그 뒤에 uniq를 붙여 확인한다.
LC_ALL=C sort -s -k1,1n ./events.txt | LC_ALL=C uniq
실제 출력에는 정확 중복이 다시 남았다.
2 gamma
10 alpha
10 beta
10 alpha
값이 10인 세 줄의 입력 순서를 보존하면서 두 10 alpha 사이에 10 beta도 남았기 때문이다. uniq 없이 실행한 sort -s -k1,1n의 결과도 이 네 줄과 같았다. 안정 정렬은 같은 키 안의 순서를 보존하는 옵션이며, 전체 입력 순서를 그대로 두거나 중복을 제거하는 기능은 아니다.
같은 숫자 안의 메시지 순서가 바뀌어도 괜찮고 정확 중복을 없애는 것이 목적이라면 앞의 sort -k1,1n | uniq를 사용한다. 키 안의 입력 순서 보존과 떨어진 중복 제거가 모두 필요하다면, 안정 정렬 뒤 단순 uniq만으로 두 요구를 충족할 수 없다. 전체 줄의 최초 등장 여부를 별도로 추적하는 처리가 필요하며 그 구현은 이 실험에서 검증하지 않았다.
이 결과는 C 로케일의 LF 줄바꿈, 숫자 첫 필드와 ASCII 메시지로 된 작은 입력에서 확인했다. BSD·BusyBox 구현, 숫자가 다른 위치에 있는 로그, 다른 비교 옵션 조합은 실행하지 않았다. 같은 명령인데 결과가 다르면 먼저 GNU 구현인지와 실제 숫자 필드 위치를 확인한다. LC_ALL=C만 붙여서는 -nu의 중복 기준이 전체 줄로 바뀌지 않는다.