내 대용량 (최대 2GiB) 텍스트 파일에는 모든 줄의 정확한 복제본이 약 100 개 포함되어 있습니다 (내 경우에는 파일이 CSV와 같은 데이터 테이블).
필요한 것은 원래 시퀀스 순서를 유지하면서 모든 반복을 제거하는 것입니다 (바람직하지만 성능 향상을 위해 희생 할 수 있음). 결과적으로 각 줄은 고유해야합니다. 만약 100 개의 동일한 라인이 있다면 (보통 중복은 파일 전체에 퍼져 있고 이웃이 아닐 것입니다) 그 종류 중 하나만 남게됩니다.
나는 Scala로 프로그램을 작성했습니다. Scala에 대해 모르는 경우 Java)를 구현합니다. 하지만이 작업을 더 빨리 수행 할 수있는 더 빠른 C 작성 기본 도구가 있습니까?
업데이트 : awk "!seen[$0]++" filename
솔루션은 파일이있는 한 저에게 잘 작동하는 것 같았습니다. 2GiB 이하에 가깝지만 8GiB 파일을 정리할 때 더 이상 작동하지 않습니다. 4GiB RAM이있는 Mac과 4GiB RAM이있는 64 비트 Windows 7 PC에서 무한대를 차지하는 것 같습니다. 그리고 6GiB 스왑은 메모리가 부족합니다. 그리고이 경험을 감안할 때 4GiB RAM이있는 Linux에서 시도하는 데 열광하지 않습니다.
댓글
답변
#bash (Freenode)에 표시된 awk
솔루션 :
awk "!seen[$0]++" filename
댓글
- 2G 파일에서이 작업을 시도했고 내 노트북에서 3 분이 걸렸습니다. 나쁘지 않다. 나는 또한 유일한 파일 이름을 시도했다 | awk ‘! seen [$ 0] ++ ‘, 그러나 ‘ 아무도 더 빠릅니다.
- @HashWizard :이 명령은 정렬되지 않지만 다음 번에 같은 줄이 나타날 때마다 제거합니다.
- 이 명령이 어떻게 작동하는지 궁금하십니까? -여기 참조 : unix.stackexchange.com/questions/159695/how-does-awk-a0-work
- @MaxWilliams yes , 효과는 무작위로 배포됩니다.
- 줄 바꿈 또는 공백이있는 줄 유지
awk '/^\s*?$/||!seen[$0]++'
답변
sort
, 대부분의 구현에서 대용량 파일에 대한 특정 최적화 (좋은 외부 정렬 알고리즘)가 있습니다. 이 방법의 장점은 특수 목적 유틸리티 내부의 모든 줄에 대해서만 반복되며 해석 된 언어 내부에서는 반복되지 않는다는 것입니다.
<input nl -b a -s : | # number the lines sort -t : -k 2 -u | # sort and uniquify ignoring the line numbers sort -t : -k 1n | # sort according to the line numbers cut -d : -f 2- >output # remove the line numbers
모든 줄이 a로 시작하는 경우 공백이 아닌 문자의 경우 다음 옵션 중 일부를 생략 할 수 있습니다.
<input nl | sort -k 2 -u | sort -k 1n | cut -f 2- >output
다량의 중복의 경우 단일 복사본 만 저장하면되는 방법 메모리의 각 줄이 더 잘 수행됩니다. 약간의 해석 오버 헤드로 “이에 대한 매우 간결한 awk 스크립트가 있습니다 (이미 enzotib에서 게시 )) :
<input awk "!seen[$0]++"
간결하지 않음 : !seen[$0] {print} {seen[$0] += 1}
. 즉, 아직 보이지 않으면 현재 줄을 인쇄 한 다음 seen
이 줄에 대한 카운터 (초기화되지 않은 변수 또는 배열 요소는 숫자 값 0을 가짐)
긴 줄의 경우 각 줄의 스푸핑 불가능한 체크섬 (예 : 암호화 다이제스트) 만 유지하여 메모리를 절약 할 수 있습니다. . 예를 들어 SHA-1을 사용하면 20 바이트와 라인 당 상수 오버 헤드 만 필요합니다. 그러나 다이제스트 계산은 다소 느립니다. 이 방법은 빠른 CPU (특히 다이제스트를 계산하는 하드웨어 가속기가있는 CPU)가 있고 파일 크기와 충분히 긴 줄에 비해 메모리가 많지 않은 경우에만 이깁니다. 기본 유틸리티로 각 라인의 체크섬을 계산할 수 없습니다. Perl / Python / Ruby /…의 해석 오버 헤드를 감당하거나 전용 컴파일 프로그램을 작성해야합니다.
<input perl -MDigest::MD5 -ne "$seen{Digest::MD5::md5($_)}++ or print" >output
댓글
- @Gilles
awk '!seen[$0]++'
에 대한 설명에 따르면 awk가 2 개의 중복 된 줄을 발견하면 항상 첫 번째 줄을 유지하고 모두 무시한다는 의미입니까? 다음 항목? (또는 마지막 항목을 유지합니까?) - @ user779159 첫 번째 항목을 유지합니다. 각 입력 행은 즉시 인쇄되거나 (첫 번째 발생) 전혀 인쇄되지 않습니다 (반복 발생).
- @ user779159 li>
- 하지만 sort -u …와 비교하면 어떻습니까?
- @HashWizard 일반
sort -u
는 순서를 변경합니다.내 대답은 순서 (정확하게는 첫 번째 발생 순서)를 보존하는 솔루션을 보여줍니다. - @Gilles 50 % 중복이있는 대용량 파일 (10G)의 경우 sort -u보다 빠르다고 말씀하겠습니까? ?
Answer
sort -u big-csv-file.csv > duplicates-removed.csv
출력 파일은 정렬됩니다.
댓글
- 다른 답변의
awk
명령만큼 빠르지는 않지만 개념적으로 간단합니다! - @Johann 저는 수십만 (심지어 백만) 개의 짧은 줄 바꿈으로 끝나는 문자열이있는 파일에서이 작업을 자주 수행합니다. 내가하는 실험에 대한 결과를 꽤 빨리 얻습니다. 반복 실행되는 스크립트에서 사용하면 더 중요 할 수 있으며 시간을 상당히 절약 할 수 있습니다.
- 정렬 중에 중복을 제거하려면
sort -u
를 사용합니다. 이후보다는. (그리고 메모리 대역폭을 절약합니다) 다른 프로그램으로 파이핑). 출력도 정렬하려는 경우awk
버전보다 낫습니다. (이 질문에 대한 OP는 원래 주문이 보존 되기를 원하므로 약간 다른 사용 사례에 대한 좋은 답변입니다.) - 잠깐 시간을내어 550 만 라인 파일 (총 1.8GB). 훌륭합니다.
답변
중복 제거 된 파일을 메모리에 보관할 여유가 있다고 가정합니다 ( 데이터가 실제로 100 배로 복제되면 약 20MiB + 오버 헤드가되어야합니다.) Perl을 사용하면 매우 쉽게이 작업을 수행 할 수 있습니다.
$ perl -ne "print unless $dup{$_}++;" input_file > output_file
이 주문도 유지합니다.
원하는 경우 %dup
해시에서 각 줄의 발생 수를 추가 무료 보너스로 추출 할 수 있습니다.
p>
awk
를 선호하는 경우이 작업도 수행해야합니다 (펄 버전과 동일한 논리, 동일한 순서, 동일한 데이터가 dup
변수) :
$ awk "{if (++dup[$0] == 1) print $0;}" input_file > output_file
댓글
- 이거 너무 좋아요 @Mat, I ㅋㅋ;-).
- 이제 그의 sed와 awk magic weavery를 위해 @ManAtWork를 기다리고 있습니다 🙂
- awk 팁을 위해 다시 굉장합니다 :- )
- perl 스크립트를 remov로만 변경할 수 있습니까? 인접한 줄이 중복됩니까?
- @dumbledad :
uniq
이 모든 작업을 자체적으로 수행합니다.
답변
인플레 이스 지원을 제공하는 다른 답변은 없지만 다음은 하나입니다.
gawk -i inplace "!a[$0]++" file
댓글
- 순서가 유지됩니까? 그건 그렇고, 이것은 나를 위해 작동하지 않았습니다. 내 버전은 다음과 같습니다.
GNU Awk 4.0.2
- @Leonid 예, 그렇습니다. 고유 한 행의 첫 번째 발생을 인쇄합니다. 인플레 이스 지원은 2013 년에 출시 된 버전 4.1에서 처음 도입되었습니다.
- 이게 답입니다. ‘ 실제로 기존 또는 현재 파일에서 중복 된 문자열을 삭제합니다. 여기에서 최상위 답변과 대부분의 답변은 고유 / 중복 된 문자열 만 출력하고 아무것도하지 않고 생성해야합니다. 결과를 저장하기위한 다른 출력입니다.
Answer
uniq
http://www.computerhope.com/unix/uuniq.htm
uniq
파일에서 반복되는 줄을보고하거나 필터링합니다.
댓글
- 답변을 제공 할 때 당신의 대답에 대한 몇 가지 설명 이 그 중 하나입니다. 그렇다면이 답변은 이전 답변과 어떻게 다른가요?
- Uniq man 페이지에서 : 참고 :
'uniq' does not detect repeated lines unless they are adjacent.
따라서 먼저 정렬하고 느슨하게해야합니다. 중복되지 않는 줄의 순서입니다.
답변
Python One 라이너 :
python -c "import sys; lines = sys.stdin.readlines(); print "".join(sorted(set(lines)))" < InputFile
댓글
- 이로 인해 전체 파일이 메모리에 저장되며 OP ‘ 문제에 적합하지 않을 수 있습니다. 또한 순서를 유지하는 것이 보장되지 않습니다.
- 제안 해 주셔서 감사합니다. ‘ 방금 파이썬을 배우고 있습니다 .. 학습 목적으로이 작업을 시도했습니다 .. 🙂
- 여기 ‘ s 는 한 줄짜리가 아니지만 (간결하게) Python 2.7 버전입니다. 전체 파일을 메모리에로드하거나 인쇄 할 하나의 거대한 문자열을 생성하지 않고 순서를 유지하는 고유 한 줄을 반환합니다.
- @ 1_CR 감사합니다. 오늘 배운 내용이 있습니다. 🙂
OrderedDict
Answer
여기에있는 답변 중 어느 것도 Mac에서 저에게 효과가 없었기 때문에 간단한 Python을 작성했습니다. 나를 위해 작동하는 스크립트. 선행 / 후행 공백을 무시하고 메모리 소비도 신경 쓰지 않습니다.
import sys inputfile = sys.argv[1] outputfile = sys.argv[2] with open(inputfile) as f: content = f.readlines() content = [x.strip() for x in content] my_list = list(set(content)) with open(outputfile, "w") as output: for item in my_list: output.write("%s\n" % item)
위의 내용을 고유하게 저장합니다.py 및 다음과 같이 실행하십시오.
python unique.py inputfile.txt outputfile.txt
답변
원래 시퀀스 순서를 유지하지 않은 솔루션
다음 코드 조각으로 작업했습니다.
sort duplicates.txt | uniq > noDuplicates.txt
sort
명령은 행을 알파벳순으로 정렬하고 uniq
명령은 중복을 제거합니다.
참고 : 라인을 먼저 정렬 한 이유는 는 인접하지 않는 한 중복 된 줄을 감지하지 않습니다.
설명
입력 순서를 유지하지 않고uniq
에 배관하는 것보다 더 효율적인 방식입니다.
sort -u
( POSIX 의 일부 임);-). 답변
연관 배열을 활용하는 순수 Bash 솔루션 인 bash 4 를 사용할 수 있습니다. 다음은 예입니다.
unset llist; declare -A llist; while read -r line; do if [[ ${llist[$line]} ]]; then continue else printf "%s\n" "$line" llist[$line]="x" fi done < file.txt
댓글
- 돈 ‘ 큰 텍스트 파일을 처리하기 위해
read
루프를 사용하지 마십시오. bash는 줄 바꿈을 초과하지 않도록 한 번에 한 바이트 씩 읽어야합니다. Bash는 또한 일반적으로 awk에 비해 텍스트 처리 속도가 빠르지 않습니다. 이것을 사용하면read -ra
입력에 백 슬래시를 사용하지 않습니다. 또한 ‘이를 셸 함수에 넣거나 루프를 실행하는 경우 루프 뒤에unset llist
뒤에 하는 것을 잊지 마십시오. 대화식으로 사용하십시오. - @PeterCordes 또는 방금 this 를 참조했을 수 있습니다. 🙂
sort -u
가 더 빠를 것입니다.