모든 하위 디렉터리의 모든 파일을 정렬하고 싶습니다. 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
목록::추가 유틸리티uniq
Perl에 대한 기능을 제공합니다(Perl에는 sort
내장 기능이 있지만 하나도 없습니다 uniq
). perl의 옵션은 -n
각 입력 레코드를 반복하지만 기본적으로 아무것도 인쇄하지 않습니다(즉, 명시적으로 인쇄된 내용만 인쇄합니다).sed
-n
스크립트는 -0
각 파일을 한 번에 삼킬 수 있도록 입력 레코드 구분 기호를 NUL(해당 옵션 사용)로 설정합니다. 그런 다음 각 입력 파일을 개행 문자로 분할하고 고유한 정렬 순서로 인쇄합니다.
List::MoreUtils
Debian(및 Ubuntu, Mint 등)의 패키지에 있으며 liblist-moreutils-perl
Fedora, 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
또는 함수 앞에 추가하면 됩니다. 예를 들어.sort
uniq
print join("\n", reverse sort keys %uniq),"\n"
아니면 당신이 가지고 있다면스펀지Joey Hess의 설치에서는 , 및 다음을 moreutils
사용할 수 있습니다 .find
shell
sort -u
sponge
find . -type f -exec sh -c \
'for f in "$@"; do sort -u "$f" | sponge "$f" ; done' find-sh {} +
이는 한 번 sh
포크 해야 하기 때문에 Perl 버전보다 훨씬 느립니다.sort
sponge
각각모든 입력 파일을 처리 perl
하기 위해 한 번(*)만 분기하는 대신 입력 파일을 처리합니다 .find
(*) 모든 파일 이름이 명령줄에 맞는다고 가정합니다. Linux에서는 약 200만 자에 해당합니다. 결합된 모든 파일 이름이 이보다 길면 Perl을 두세 번(또는 그 이상) 분기해야 할 수도 있습니다.
sh
여러 번 포크해야 하는 포크 에도 동일하게 적용됩니다 . 그러나 find
sh(또는 perl)를 몇 번 포크하는 비용은 합계를 포크하는 비용에 비해 무시할 수 있습니다.sort
sponge
파일당 한 번. 대신 +
with 를 사용하면 시간이 절약됩니다 .find ... -exec ... {}
\;