재귀적으로 제자리 정렬 및 중복 제거

재귀적으로 제자리 정렬 및 중복 제거

모든 하위 디렉터리의 모든 파일을 정렬하고 싶습니다. 256개의 디렉터리에 65536개의 파일이 있고 각 파일에는 한 줄에 한 단어가 포함되어 있으며 각 파일에는 중복 항목이 포함되어 있습니다.

내가 원하는 것은 -u 옵션을 사용하여 이러한 항목을 정렬하는 것입니다(이유는 모르겠지만 정렬을 uniq -u 명령에 전달하면 실제로 중복된 고유 줄이 제거되는데 이상하지만 어쨌든). 이렇게 하면 어떤 출력 파일도 원하지 않습니다. 메모리에 있는 파일을 정렬하여 읽은 다음 덮어쓰고 싶습니다. -o 옵션을 시도했지만 파일 이름이 필요합니다.

이 작업을 재귀적으로 수행할 수 있는 방법이 있나요?

감사해요:)

답변1

그것은 다음과 같을 수 있습니다:

find . -type f -size +1c -exec sort -uo {} {} ';'

(2바이트 미만의 파일은 여기에서 건너뜁니다. 두 개의 개별 라인을 만들려면 최소 3바이트가 필요하거나 "\nx"공백 라인과 무제한 라인 1이 뒤따르는 2바이트가 필요할 수 있기 때문입니다.)

기본 정렬 순서는 sort로케일의 데이터 정렬 알고리즘을 기반으로 합니다.

두 줄은 바이트 단위가 동일하지 않더라도 동일하게 정렬할 수 있습니다. 특히 줄에 유효한 문자를 형성하지 않는 바이트 시퀀스가 ​​포함되어 있고 GNU 시스템(예: Debian)에서는 정렬 순서가 동일하지 않은 경우 더욱 그렇습니다. 문자에 대해서도 동일하게 정의된 대로 정렬됩니다.

넌 할 수있어:

LC_ALL=C find . -type f -exec sort -uo {} {} ';'

대조적으로, ASCII 기반 시스템(예: 모든 아키텍처 및 커널에 대한 Debian)에서 C 로케일의 대조는 로케일 정렬 순서가 아닌 바이트 값을 기반으로 합니다(또는 IOW, C 로케일의 대조는 바이트 값을 기반으로 합니다). ) 행은 정렬되며, 바이트가 다른 두 행이 동일하게 정렬되지 않도록 보장되어야 합니다.

sort이는 파일당 하나의 호출을 실행합니다. 파일이 매우 짧은 경우 작업 속도를 높이기 위해 다음을 수행할 수 있습니다 zsh.

zmodload zsh/mapfile
for f (**/*(N.)) print -rC1 -v 'mapfile[$f]' - ${(fou)mapfile[$file]}

sort이렇게 하면 외부 명령을 여러 번 실행하는 것을 방지하고 대신 o매개변수 u확장 플래그를 사용하여 행을 정렬하고 고유하게 정렬합니다. 입력에서 빈 줄(있는 경우)을 제거하고 숨겨진 파일을 건너뜁니다( D필요한 경우 glob 한정자를 추가합니다).

GNU 와는 달리 sort -u바이트 zsh단위로 동일하지 않은 두 문자열은 중복으로 간주되지 않으므로(동일하게 정렬된 경우에도) 로케일을 C로 수정할 필요가 없습니다.

$ 로케일 헤더 문자 맵
영국식 영어 환경
UTF-8
$a=(

답변2

$ find . -type f -exec perl -MList::MoreUtils=uniq -i -0 -n -e \
    'print join("\n", uniq split /\n/), "\n"' {} +

이는 내부 편집 옵션을 사용하여 find파일 이름을 스크립트 에 전달하는 데 사용됩니다 .perl-i목록::추가 유틸리티uniqPerl에 대한 기능을 제공합니다(Perl에는 sort내장 기능이 있지만 하나도 없습니다 uniq). perl의 옵션은 -n각 입력 레코드를 반복하지만 기본적으로 아무것도 인쇄하지 않습니다(즉, 명시적으로 인쇄된 내용만 인쇄합니다).sed-n

스크립트는 -0각 파일을 한 번에 삼킬 수 있도록 입력 레코드 구분 기호를 NUL(해당 옵션 사용)로 설정합니다. 그런 다음 각 입력 파일을 개행 문자로 분할하고 고유한 정렬 순서로 인쇄합니다.

List::MoreUtilsDebian(및 Ubuntu, Mint 등)의 패키지에 있으며 liblist-moreutils-perlFedora, Centos 또는 RHEL에도 비슷한 패키지 이름이 있을 수 있습니다. 다른 배포판에서도 이를 패키지화할 수 있습니다. 그렇지 않으면 CPAN에서 설치하십시오.

를 설치하고 싶지 않거나 설치할 수 없는 경우 List::MoreUtils연관 배열("해시"라고도 함)을 사용할 수 있습니다. 예를 들어

$ find . -type f -exec perl -i -0 -n -e \
    '%uniq = map {$_ => 1} split /\n/;
     print join("\n", sort keys %uniq), "\n"' {} +

먼저 일부 정크 파일에서 이들 중 하나를 실행하여 원하는 대로 작동하는지 확인하겠습니다. 및/또는 -i표준 출력으로 인쇄되도록 옵션 없이 테스트합니다. junk다음 내용이 포함된 파일에서 테스트했습니다 .

6
5
5
4
3
2
1
1

위 버전 중 하나를 실행한 후 다음을 junk포함합니다.

1
2
3
4
5
6

역순으로 하려면 reverse또는 함수 앞에 추가하면 됩니다. 예를 들어.sortuniqprint join("\n", reverse sort keys %uniq),"\n"


아니면 당신이 가지고 있다면스펀지Joey Hess의 설치에서는 , 및 다음을 moreutils사용할 수 있습니다 .findshellsort -usponge

find . -type f -exec sh -c \
  'for f in "$@"; do sort -u "$f" | sponge "$f" ; done' find-sh {} +

이는 한 번 sh포크 해야 하기 때문에 Perl 버전보다 훨씬 느립니다.sortsponge각각모든 입력 파일을 처리 perl하기 위해 한 번(*)만 분기하는 대신 입력 파일을 처리합니다 .find

(*) 모든 파일 이름이 명령줄에 맞는다고 가정합니다. Linux에서는 약 200만 자에 해당합니다. 결합된 모든 파일 이름이 이보다 길면 Perl을 두세 번(또는 그 이상) 분기해야 할 수도 있습니다.

sh여러 번 포크해야 하는 포크 에도 동일하게 적용됩니다 . 그러나 findsh(또는 perl)를 몇 번 포크하는 비용은 합계를 포크하는 비용에 비해 무시할 수 있습니다.sortsponge 파일당 한 번. 대신 +with 를 사용하면 시간이 절약됩니다 .find ... -exec ... {}\;

관련 정보