[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. LOAD를 만들기 위해 실행되는 다른 것은 없습니다. 몇 초 후에 Awk가 중단됩니다. out.txt는 ~ 1.6GB입니다. GNU Awk 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과 다른 이유는 무엇입니까?
업데이트 : 우분투 14 가상 게임을 시도하고 있습니다. 지금까지는 작동합니다! 그것은 ulimit 문제가 아닙니다 : mawk 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:~#
답변
나는 그것이 차이를 만들지 의심하지만, 만약을 대비하여 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
줄 번호는 각 줄 앞에 약간의 공백을두고 <tab> 문자를 붙입니다.cat
이 입력 표현을로 파이프합니다sort
. -
sort
의-k2
옵션은 단지 라인이 끝날 때까지 정렬 때 두 번째 필드에서 문자를 고려하도록 지시sort
분할 공백에 기본적으로 필드 (또는cat
의 삽입 공간을하고 ‘를 <탭> ) .
다음에 할 때-k1n
,sort
먼저 2 필드를 고려하고 둘째-에서 동일의 경우-k2
필드-는 1 필드를 고려하지만, 수치 적으로 분류한다. 따라서 반복되는 줄은 함께 정렬되지만 순서대로 나타납니다. - 결과는
uniq
첫 번째 필드 (-f1
및 공백으로 구분됨) 를 무시하도록 파이프되고 원본 파일에 고유 한 행 목록이 생성되어 다시 파이프됩니다sort
. - 이 시간
sort
는 첫 번째 필드 (cat
삽입 된 줄 번호)를 숫자로 정렬하여 정렬 순서를 원래 파일에 있던 순서로 다시 가져 와서이 결과를로 파이프합니다cut
. - 마지막으로
cut
에 의해 삽입 된 줄 번호를 제거합니다cat
. 이는cut
두 번째 필드에서 줄 끝까지 만 인쇄하여 적용됩니다 (및cut
기본 구분 기호는 <tab> 문자 임) .
설명하기 위해 :
$ 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
답변
#!/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
Case1 : 100_000_000 난수 (각 5 자리), 566Mbytes, 31_212 개의 다른 값 :
$ while true ; do echo $RANDOM; done | head -100000000 > _1
사례 2 : 50_000_000 랜드 번호 (각 10 자리), 516MB, 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
환상적인 명령입니다!
답변
나는 사용했다
awk -v BINMODE=rw '!($0 in a){a[$0];print}' infile >> outfile
BINMODE = rw : 줄 끝 종결자를 만족시킵니다. (혼합 OS 환경에 살고 있습니다)
논리는 간단합니다.
현재 행이 연관 배열에 없으면 연관 배열에 추가하고 출력으로 인쇄하십시오.
이 방법에는 메모리 제한이있을 수 있습니다. 매우 큰 파일과 파일 세트의 경우 파일 저장소를 사용하여 한계를 극복하기 위해 변형을 사용했습니다.
답변
문제의 순서 유지 의미론에는 놀라운 속성이 있습니다. 문제를 세분화 할 수 있습니다. split -l 1000000
입력 파일에서 수행 할 수 있습니다 . 그것이 생산하는 1000000 라인 조각은 어휘 적으로 정렬 된 이름을 가지고 있습니다. 그런 다음 조각을 uniqify; 그런 다음 (두 번째 단계로) 출력을 uniqify하십시오.
이는 멀티 패스 솔루션으로 전환하는 대신 메모리 부족 문제 (메모리 요구량 상한)를 해결합니다.
구체적으로 특별히:
입력 데이터를 생성하십시오.
$ cat make-uniqm-input.py
#!/usr/bin/env python
import random
n = 1000000
for i in xrange(0, n):
print random.randint(1000, 2000)
$ python make-uniqm-input.py > uniqm-input.txt
$ wc -l uniqm-input.txt
1000000 uniqm-input.txt
입력 데이터를 분할하십시오.
$ split -l 10000 uniqm-input.txt
$ ls x?? | head
xaa
xab
xac
xad
xae
xaf
xag
xah
xai
xaj
$ ls x?? | wc -l
100
$ cat x?? | wc -l
1000000
uniqifier를 한 번에 모두 실행하십시오 (메모리에 모든 고유 한 입력 라인을 유지).
# 'uniqm' is any order-preserving uniq implementation, such as
# gawk '!counts[$0]++'.
$ uniqm < uniqm-input.txt > output-no-splitting.txt
$ wc -l output-no-splitting.txt
1001 output-no-splitting.txt
분할 조각에서 uniqifier를 실행 한 다음 (메모리의 각 조각에서 고유 한 입력 라인 만 유지) 두 번째 패스로 줄이십시오.
$ for x in x??; do uniqm < $x; done | uniqm > output-with-splitting.txt
$ wc -l output-with-splitting.txt
1001 output-with-splitting.txt
비교:
$ diff output-no-splitting.txt output-with-splitting.txt
$ head uniqm-input.txt
1506
1054
1623
1002
1173
1400
1226
1340
1824
1091
$ head output-with-splitting.txt
1506
1054
1623
1002
1173
1400
1226
1340
1824
1091
입력에서 고유하지 않은 라인과 고유하지 않은 라인의 비율 또는 입력 라인의 혼합 비율을 알지 못하므로 필요한 분할 파일 수와 관련하여 약간의 조정이 있습니다.
답변
다른 접근법 (별도의 답변으로 게시해야 함)은 임시 파일을 생성하는 분할 파일 방식 대신 uniqifier 소프트웨어 자체에서 일괄 처리를 수행합니다. 예를 들어, 설명을 위해 Ruby uniqifier 구현을 사용하는 경우 :
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 줄마다 배열을 지울 수 있습니다. 이러한 모든 언어에 대해 명확한 방법이 있습니다. 나는 생각 awk
들 ‘ delete
비표준하지만 일반적입니다.