특정 열의 모든 파일에 패턴이 한 번만 포함된 경우 행을 삭제하는 방법

특정 열의 모든 파일에 패턴이 한 번만 포함된 경우 행을 삭제하는 방법

내 파일에는 여러 열이 포함되어 있으며 첫 번째 열은 ID에 해당합니다. 전체 파일에서 ID가 한 번만 나타나는 경우(첫 번째 열) 행을 삭제하고 싶습니다. ID가 여러 번 나타나면 해당 줄을 파일에 유지하고 싶습니다. ID는 A로 시작하는 문자(때로는 숫자)로 구성됩니다(다른 모든 문자/숫자는 무작위 순서입니다). 예를 들어:A2SGWS7CUGU8GB

만약 내가 가지고 있다면:

# id             #column 2 ...
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
ADE8GST9URWPOS
ABXLMWJCQFGVXV
A2SGWS7CUGU8GB

ADE8GST9URWPOS및 가 포함된 줄은 ABXLMWJCQFGVXV한 번만 나타나므로 삭제하고 싶습니다 . 어떻게 해야 하나요?

답변1

먼저, 유지하려는 모든 중복 ID가 반환됩니다.

$ awk '{ print $1 }' <file | sort | uniq -d
A2SGWS7CUGU8GB

를 사용하여 첫 번째 공백으로 구분된 필드(ID)를 추출하여 이를 수행합니다 awk. 그런 다음 이를 정렬하여 uniq -d중복된 ID만 출력하는 데 사용됩니다.

그런 다음 이러한(이 경우 단일) ID를 사용하여 원본 파일에서 해당 줄을 추출할 수 있으며, 먼저 다음을 사용하여 정렬해야 합니다 join.

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file )
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

쉘이 <(...)임시 파일을 사용한 프로세스 교체를 지원하지 않는 경우 임시 파일을 사용하여 두 단계로 이를 수행할 수 있습니다.

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

사용오직 awk, 이는 다음을 통해 수행할 수 있습니다.

$ awk 'NR == FNR { count[$1]++; next } count[$1] > 1' file file
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

코드가 파일을 두 번 읽기 때문에 명령줄에서 파일이 두 번 언급됩니다 awk.

처음에는 연관 배열이 count각 ID의 발생 횟수로 채워지고, 두 번째에는 ID가 여러 번 발생하는 각 행이 출력됩니다.

위 두 방법의 차이점은 awk마지막 명령이 원본 데이터의 순서를 유지하지만 고유 ID 수에 비례하여 메모리를 소비한다는 것입니다. 첫 번째 접근 방식은 정렬된 결과를 생성하므로 더 적합할 수 있습니다.매우 크다데이터.


헤더 행을 유지하려면 명령을 약간 수정해야 합니다.

$ join <( awk '{ print $1 }' <file | sort | uniq -d ) <( sort file ) | cat <(head -1 file) -

또는

$ sort -o file.sorted file
$ awk '{ print $1 }' <file | sort | uniq -d | join - file.sorted > file.noheader
$ head -1 file | cat - file.noheader

또는

$ awk 'NR == 1 ; NR == FNR { count[$1]++; next } count[$1] > 1' file file

답변2

awk '
  !B {a[$1]++}
  B && a[$1] > 1
' B=0 file B=1 file

첫 번째 필드(=ID)를 가져와 정렬한 다음 ID를 통합하고 중복된 항목만 유지합니다. 이를 xargs에 전달하고 각 ID를 기반으로 egrep ERE 정규식을 만듭니다.

< file \
  cut -d" " -f1          \
| sort  | uniq -d        \
| xargs -I{} echo ^{}\\s \
| grep -Ef - file        \
;

perlslurp 파일 옵션을 사용 -0777하고 레코드를 통해 정규식을 실행하면 각 줄의 시작 부분에서 ^더 아래에 있는 첫 번째 필드(=ID)를 볼 수 있거나 ID가 이전에 발견된 경우 현재 줄을 인쇄합니다.

perl -0777ne '
  () = m/(?msx)
      ^
      (?<line>
        (?<ID> A\w+)
        \h.*?\n
      )

      (?=
        (?:.*?\n)?
        (?<lukahead> \g{ID}|$)
      )

      (?{ my %seen;
        my($id_visible_ahead, $id_already_seen) =
          map { $_ > 0 } 
length($+{lukahead}), $seen{$+{ID}};

        print($+{line}),$seen{$+{ID}}++
          if $id_visible_ahead || $id_already_seen;
      })
   /g;
' file

산출:

A2SGWS7CUGU8GB
A2SGWS7CUGU8GB
A2SGWS7CUGU8GB

관련 정보