대용량 텍스트 파일을 효율적으로 병합/정렬/고유

대용량 텍스트 파일을 효율적으로 병합/정렬/고유

나는 순진한 노력을 기울이고 있습니다.

$ cat * | sort -u > /tmp/bla.txt

실패:

-bash: /bin/cat: Argument list too long

따라서 (거대한 임시 파일 생성)과 같은 어리석은 솔루션을 피하려면 다음을 수행하십시오.

$ find . -type f -exec cat {} >> /tmp/unsorted.txt \;
$ cat /tmp/unsorted.txt | sort -u > /tmp/bla.txt

다음을 사용하여 파일을 하나씩 처리할 수 있습니다(이렇게 하면 메모리 소비가 줄어들고 스트리밍 메커니즘에 더 가까워집니다).

$ cat proc.sh
#!/bin/sh
old=/tmp/old.txt
tmp=/tmp/tmp.txt
cat $old "$1" | sort -u > $tmp
mv $tmp $old

다음은 다음과 같습니다.

$ touch /tmp/old.txt
$ find . -type f -exec /tmp/proc.sh {} \;

더 간단하고 유닉스 스타일의 대안이 있습니까? cat * | sort -u파일 수에 도달했을 때 MAX_ARG? 이러한 일반적인 작업을 위해 작은 쉘 스크립트를 작성하는 것은 어색합니다.

답변1

최소한 Bash에서는 작동하는 간단한 수정입니다. printf내장되어 있고 명령줄 인수 제한이 적용되지 않기 때문입니다.

printf "%s\0" * | xargs -0 cat | sort -u > /tmp/bla.txt

( echo * | xargs공백 등이 포함된 파일 이름을 처리하는 것을 제외하고도 작동합니다.)

답변2

GNU sort및 내장 셸 사용 printf(현재 일부 변형을 제외한 모든 POSIX 유사 셸 pdksh):

printf '%s\0' * | sort -u --files0-from=- > output

이제 한 가지 문제는 이 파이프라인의 두 구성 요소가 동시에 독립적으로 실행되기 때문에 왼쪽 구성 요소가 glob을 확장할 때 *오른쪽 구성 요소가 이미 output파일을 생성했을 수 있다는 것 입니다 -u. output입력 파일은 출력 파일이므로 출력을 다른 디렉터리( > ../output예:)로 이동하거나 glob이 출력 파일과 일치하지 않는지 확인해야 할 수 있습니다.

이 경우 문제를 해결하는 또 다른 방법은 다음과 같이 작성하는 것입니다.

printf '%s\0' * | sort -u --files0-from=- -o output

이렇게 하면 쓰기용으로 sort열리지만 output(내 테스트에서는) 전체 파일 목록을 수신할 때까지(글로브가 확장된 후 오랜 시간이 흐른 후) 작동하지 않습니다. output또한 읽을 수 있는 입력 파일이 없는 경우에도 손상을 방지합니다.

그것을 쓰는 또 다른 방법은 zshor로 쓰는 것 입니다.bash

sort -u --files0-from=<(printf '%s\0' *) -o output

이는 프로세스 대체를 사용하여 수행됩니다(여기서 <(...)대체는 printf기록되는 파이프의 읽기 끝을 참조하는 파일 경로로 대체됩니다). 이 함수는 ksh에서 왔지만 ksh개별 인수를 <(...)명령으로 확장해야 하므로 구문과 함께 사용할 수 없습니다 --option=<(...). 그러나 다음 구문을 사용할 수 있습니다.

sort -u --files0-from <(printf '%s\0' *) -o output

cat파일이 줄 바꿈으로 끝나지 않으면 파일에 제공된 출력에 대한 다른 접근 방식을 볼 수 있습니다.

$ printf a > a
$ printf b > b
$ printf '%s\0' a b | sort -u --files0-from=-
a
b
$ printf '%s\0' a b | xargs -r0 cat | sort -u
ab

또한 sort정렬은 로케일( )의 데이터 정렬 알고리즘을 사용하여 수행되며 strcollate()바이트 sort -u수준의 고유 행이 아닌 해당 알고리즘으로 정렬된 각 행 집합 중 하나를 보고합니다. 바이트 수준에서 고유한 행에만 관심이 있고 정렬 순서에 대해서는 크게 신경 쓰지 않는 경우 정렬이 바이트 값을 기반으로 하는 C로 로케일을 수정하는 것이 좋습니다( memcmp(); 이렇게 하면 속도가 빨라질 수 있습니다. 상황이 크게 개선되었습니다):

printf '%s\0' * | LC_ALL=C sort -u --files0-from=- -o output

답변3

find . -maxdepth 1 -type f ! -name ".*" -exec cat {} + | sort -u -o /path/to/sorted.txt

이렇게 하면 현재 디렉토리에서 숨겨지지 않은 모든 일반 파일을 연결하고 결합된 내용을 (중복 줄을 제거하면서) 파일로 정렬합니다 /path/to/sorted.txt.

답변4

@ilkkachu와 비슷하지만 cat(1)은 필요하지 않습니다.

printf "%s\0" * | xargs -0 sort -u

또한 데이터가 매우 긴 경우 sort(1) 옵션을 사용하는 것이 좋습니다. - 평행선=질소

언제질소컴퓨터의 CPU 수입니다.

관련 정보