다음과 같이 연속적인 중복 항목을 포함하는 두 개의 열이 있는 매우 긴 CSV 파일이 있습니다.
...
1500,1533
1554,1678
1554,1703
1554,1728
1593,1766
...
마지막 항목을 제외한 모든 중복 항목을 제거해야 합니다. 따라서 위 예제의 출력은 다음과 같습니다.
...
1500,1533
1554,1728
1593,1766
...
또한 파일의 나머지 줄을 원래 순서대로 유지해야 합니다.
나는 노력했다tac file.csv | sort -k1,1 -r -u -t,
그러나 이것은 예상된 결과를 제공하지 않으며 정렬 기반 기능이 내 행 순서를 엉망으로 만듭니다.
답변1
그리고 sed
:
sed '$!N;/\(.*,\).*\n\1/!P;D' infile
N
즉, 패턴 공간에는 항상 두 개의 연속 라인이 있으며, sed
P
그 중 첫 번째 라인은 해당 라인의 첫 번째 필드가 두 번째 라인의 첫 번째 필드와 다른 경우에만 인쇄됩니다. 그런 다음 D
패턴 공간에서 첫 번째 줄을 제거하고 루프를 다시 시작합니다.
또 다른 방법은gnu datamash
(파일이 datamash
정렬되어야 하는 입력에 따라 정렬되어 있다고 가정):
datamash -t ',' -g 1 last 2 <infile
이렇게 하면 g
구분된 입력이 st 필드로 그룹화되고 각 그룹의 값(nd 열부터)만 인쇄됩니다.,
1
last
2
파일이 정렬되지 않은 경우 다음 datamash
기준으로 정렬할 수 있습니다 -s
.
datamash -t ',' -s -g 1 last 2 <infile
그러나 이는 행의 초기 순서가 유지되지 않음을 의미합니다. 따라서 원하는 효과가 없을 수도 있습니다. 이 경우 sed
// awk
등을 사용할 수 있습니다 perl
.
답변2
awk에 대한 대안도 있습니다:
awk -F, 'NR==1{old=$0;check=$1}NR>1 && $1 != check {print old}{old=$0;check=$1}END{print old}' knovice
1500,1533
1554,1728
1593,1766
답변3
다른 방법이 있습니다 awk
(감사합니다@글렌):
tac file | awk -F, 'awk -F, '!seen[$1]++' | tac
구분 기호를 설정합니다 -F,
. 에서 awk
표현식이 true로 평가되면 기본 작업은 현재 줄을 인쇄하는 것입니다. !seen[$1]
배열에 첫 번째 필드가 없으면 true입니다 seen
. 그러나 우리도 그것을 만들었기 때문에 seen[$1]++
처음 볼 때만 틀릴 것입니다. 결과적으로 첫 번째 사본만 인쇄됩니다.
위 스크립트는 반복적으로 실행될 때마다 마지막 스크립트 대신 첫 번째 스크립트를 유지하므로 이 두 tac
호출은 순서를 뒤집어 마지막 스크립트를 유지하도록 만드는 추악한 해킹입니다. 2개이므로 최종 순서는 바뀌지 않습니다.
답변4
Miller( mlr
)를 사용하여 첫 번째 필드로 그룹화하면서 각 그룹의 마지막 항목을 가져옵니다.
$ mlr --csv -N tail -n 1 -g 1 file
1500,1533
1554,1728
1593,1766
위 명령에서 간단히 으로 변경하면 마지막 두 개를 얻을 수 있습니다 tail -n 1
.tail -n 2