[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-
작동 방식:
GNU 시스템에서는
cat -n
각 줄 앞에 줄 번호가 오고 그 뒤에 공백이 옵니다.<탭>특징.cat
이 입력 표현을sort
.sort
옵션은-k2
정렬 시 두 번째 필드부터 줄 끝까지의 문자만 고려하고sort
기본적으로 공백으로 필드를 분할하도록 지시합니다.(또는cat
공백을 삽입하고<탭>).
따를 때-k1n
두sort
번째 필드가 먼저 고려되고, 그 다음(-k2
동일한 필드의 경우) 첫 번째 필드가 고려되지만 숫자로 정렬됩니다. 따라서 중복된 행은 나타나는 순서대로 함께 정렬됩니다.- 결과는 다음으로 파이프됩니다
uniq
. 첫 번째 필드를 무시하라는 메시지가 표시됩니다.(-f1
- 공백으로 구분할 수도 있음)- 원본 파일의 고유한 줄 목록을 생성하고 이를 다시sort
. - 이번에는
sort
첫 번째 필드를 정렬합니다.(cat
줄 번호 삽입)수치적으로 정렬 순서를 원본 파일의 순서로 복원하고 결과를cut
. - 마지막으로
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_seen
awk, python, perl, C++ 등을 사용하든 N 행마다 배열을 지울 수 있습니다. 이 언어들은 모두 set-clear 메소드를 가지고 있습니다. 저는 awk
이것이 delete
표준은 아니지만 공통적이라고 생각합니다.