CSV의 필드에 중복된 값이 있는 연속 행을 제거하고 마지막 행은 유지합니다.

CSV의 필드에 중복된 값이 있는 연속 행을 제거하고 마지막 행은 유지합니다.

다음과 같이 연속적인 중복 항목을 포함하는 두 개의 열이 있는 매우 긴 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 열부터)만 인쇄됩니다.,1last2


파일이 정렬되지 않은 경우 다음 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

관련 정보