행 순서를 유지하면서 중복 행 제거

행 순서를 유지하면서 중복 행 제거
[root@server]# awk '!seen[$0]++' out.txt > cleaned
awk: (FILENAME=out.txt FNR=8547098) fatal error: internal error
Aborted
[root@server]#

"서버"에는 8GB RAM + 16GB SWAP, x>300GB 여유 공간, amd64, 데스크톱 CPU가 있습니다. 사이언티픽 리눅스 6.6. 그 위에 로드할 다른 실행 항목이 없습니다. 몇 초 후에 awk가 중단됩니다. out.txt는 약 1.6GB입니다.GNU 깨어 3.1.7.

질문: 행 순서를 유지하면서 중복 행을 제거하는 방법은 무엇입니까? 대소문자도 중요합니다. 예를 들어 "A"와 "a"는 서로 다른 두 줄이므로 유지해야 합니다. 그러나 "a"와 "a"는 중복되므로 첫 번째 항목만 필요합니다.

대답은 무엇이든 될 수 있습니다. awk가 이에 적합하지 않다면.. perl/sed.. 무엇이 문제가 될까요?

[root@server]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 61945
max locked memory       (kbytes, -l) 99999999
max memory size         (kbytes, -m) unlimited
open files                      (-n) 999999
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 99999999
cpu time               (seconds, -t) unlimited
max user processes              (-u) 61945
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[root@server]# 

업데이트: RHEL 시스템에서 이 작업을 시도했는데 중단되지는 않았지만 완료될 때까지 기다릴 시간이 없습니다. SL Linux가 RHEL과 다른 이유는 무엇입니까?

업데이트: Ubuntu 14 가상 머신을 사용해 보고 있습니다. 지금까지는 작동합니다! 이것은 ulimit 문제가 아닙니다.모크 1.3.3

root@asdf-VirtualBox:~# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 51331
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 51331
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
root@asdf-VirtualBox:~# 

답변1

이것이 차이를 가져올지는 의문이지만 만일을 대비해 Perl에서 동일한 작업을 수행하는 방법은 다음과 같습니다.

perl -ne 'print if ++$k{$_}==1' out.txt

문제가 메모리에 고유 행을 유지하는 것이라면 awk시도한 것과 동일한 문제가 발생합니다. 따라서 또 다른 접근 방식은 다음과 같습니다.

cat -n out.txt | sort -k2 -k1n  | uniq -f1 | sort -nk1,1 | cut -f2-

작동 방식:

  1. GNU 시스템에서는 cat -n각 줄 앞에 줄 번호가 오고 그 뒤에 공백이 옵니다.<탭>특징. cat이 입력 표현을 sort.

  2. sort옵션은 -k2정렬 시 두 번째 필드부터 줄 끝까지의 문자만 고려하고 sort기본적으로 공백으로 필드를 분할하도록 지시합니다.(또는 cat공백을 삽입하고<탭>).
    따를 때 -k1nsort번째 필드가 먼저 고려되고, 그 다음( -k2동일한 필드의 경우) 첫 번째 필드가 고려되지만 숫자로 정렬됩니다. 따라서 중복된 행은 나타나는 순서대로 함께 정렬됩니다.

  3. 결과는 다음으로 파이프됩니다 uniq. 첫 번째 필드를 무시하라는 메시지가 표시됩니다.( -f1- 공백으로 구분할 수도 있음)- 원본 파일의 고유한 줄 목록을 생성하고 이를 다시 sort.
  4. 이번에는 sort첫 번째 필드를 정렬합니다.( cat줄 번호 삽입)수치적으로 정렬 순서를 원본 파일의 순서로 복원하고 결과를 cut.
  5. 마지막으로 cut삽입된 줄 번호를 삭제합니다 cat. 이는 cut두 번째 필드부터 줄 끝까지만 인쇄하면 가능합니다.( cut기본 구분 기호는 다음과 같습니다.<탭>특징).

표시하려면:

$ cat file
bb
aa
bb
dd
cc
dd
aa
bb
cc
$ cat -n file | sort -k2 | uniq -f1 | sort -k1 | cut -f2-
bb
aa    
dd
cc

답변2

#!/usr/bin/perl 
use DB_File;
tie %h, 'DB_File';

while(<>){ not $h{$_} and print and $h{$_}=1 }

편집 1:정말 효과가 있나요? (비교하다)

Sol1 : Terdon et all Schwartzian-transform-like one-liner
    cat -n _1 | sort -uk2 | sort -nk1 | cut -f2-

Sol2 : perl  + DB_File (this answer)
    perl dbfile-uniq _1

Sol3 : PO (John W. Gill solution has a similar behavior)
    awk '!seen[$0]++' _1

Sol4: Terdon perl
    perl -ne 'print if ++$k{$_}==1' _1

사례 1:100_000_000개의 난수(각각 5비트), 566Mbytes, 31_212개의 다른 값:

$ while true ; do echo $RANDOM; done | head -100000000 > _1

사례 2: 50_000_000개의 난수(각각 10비트), 516Mbytes, 48_351_464개의 다른 값:

$ shuf _1 |  sed 'N;s/\n/ /' > _11

(다음 숫자는 매우 정확하지 않습니다):

┌────────┬────────┬────────────────┬────────┬──────┐
│        │ Sol1   │ Sol2           │ Sol3   │ Sol4 │
│        │ sort...│ perl DB        │ awk    │ perl │
├────────┼────────┼────────────────┼────────┼──────┤
│ case 1 │ 6m15   │ 6m17           │ 0m28   │ 0m28 │
├────────┼────────┼────────────────┼────────┴──────┤
│ case 2 │ 11m15  │ 81m44          │ out of memory │
├────────┼────────┼────────────────┼────────┬──────┤
│ case 2 │        │ 5m54 /cache=2G │        │      │
└────────┴────────┴────────────────┴────────┴──────┘

캐시가 있는 sol2는 다음과 같습니다.

use DB_File;
use Fcntl ;

$DB_HASH->{'cachesize'} = 2000_000_000;
tie %h, 'DB_File', "_my.db", O_RDWR|O_CREAT|O_TRUNC, 0640, $DB_HASH;

while(<>){ not $h{$_} and print and $h{$_}=1 }

캐시 크기 옵션을 추가하여 정렬을 최적화할 수도 있습니다(아직 완료되지 않음).

간단한 결론:

  • sort이것은 훌륭한 명령입니다!

답변3

나는 사용했다

awk -v BINMODE=rw '!($0 in a){a[$0];print}' infile >> outfile

BINMODE=rw : 줄 끝 종료자를 행복하게 유지합니다. (저는 혼합 OS 환경에 살고 있습니다)

논리는 간단합니다.

현재 행이 연관 배열에 없으면 연관 배열에 추가되어 출력에 인쇄됩니다.

이 방법에는 메모리 제한이 있을 수 있습니다. 매우 큰 파일과 파일 세트의 경우 제한 사항을 극복하기 위해 파일 저장소를 사용하는 변형을 사용했습니다.

답변4

별도의 답변으로 게시할 가치가 있는 또 다른 접근 방식은 임시 파일을 생성하는 분할 파일 방법을 사용하는 대신 uniqifier 소프트웨어 자체 내에서 일괄 처리를 수행하는 것입니다. 예를 들어 Ruby 고유 식별자 구현을 사용하여 다음을 설명합니다.

require 'set'
line_batch_count = 50000 # tunable parameter
lines_seen = Set.new
line_number = 0
ARGF.each do |line|
   line_number += 1
   if (line_number % line_batch_count) == 0
     lines_seen.clear
   end
   unless lines_seen.include? line
      puts line
      lines_seen << line
   end
end

해시 세트를 자주 지우는 것이 아이디어입니다. 그러면 이는 반복적이 됩니다.

$ cat uniqm-input.txt | ruby uniqm-capped.rb | wc -l
   20021

$ cat uniqm-input.txt | ruby uniqm-capped.rb | ruby uniqm-capped.rb | wc -l
    1001

$ cat uniqm-input.txt | ruby uniqm-capped.rb | ruby uniqm-capped.rb | head
1506
1054
1623
1002
1173
1400
1226
1340
1824
1091

따라서 한 반복에서 다음 반복까지 행 수가 변경되지 않을 때까지 이 제한된 버전을 반복적으로 실행할 수 있습니다.

이 capped-uniqm 기술은 언어 독립적입니다. lines_seenawk, python, perl, C++ 등을 사용하든 N 행마다 배열을 지울 수 있습니다. 이 언어들은 모두 set-clear 메소드를 가지고 있습니다. 저는 awk이것이 delete표준은 아니지만 공통적이라고 생각합니다.

관련 정보