하위 디렉토리에서 파일을 찾고 단일 명령으로 파일 이름으로 정렬하는 방법은 무엇입니까?


9

다음을 사용하여 일반 찾기 결과 find . ! -path "./build*" -name "*.txt":

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

그리고 다음과 sort -n같이 정렬하면 :

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

그러나 원하는 출력은 다음과 같습니다.

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

즉 , 파일 이름 만 기준으로 출력이 정렬 되지만 폴더 정보는 출력의 일부로 유지되어야합니다.

편집 : 서브 디렉토리 구조에 둘 이상의 레벨이 포함될 수 있으므로 예제를 더 복잡하게 만드십시오.


2
SO에 대해이 질문을 참조하십시오 : stackoverflow.com/questions/3222810/…
camh

@camh-가능하다면 유닉스 명령어 만 사용하고 싶습니다. 어쨌든 내 질문은 거의 당신의 질문입니다. 솔루션으로 표시 할 수 있도록이 스레드에 최상의 솔루션을 전송할 수 있습니까 (어쨌든 원본에 대한 링크를 유지하십시오)?
unode

@Shawn이 내 의견에서 제안한 변경 사항 ( ) -printf대신 사용 awk하면 이것이 최선의 해결책이라고 생각합니다. 이 방법을 사용하기 위해 원래 구현을 재 작업했습니다.
camh

답변:


9

마지막 필드를 기준으로 정렬해야합니다 ( /필드 구분 기호로 간주 ). 불행히도 필자는 필드 수가 다양 sort -k할 때 (음수 값만 취할 수있는 경우)이 작업을 수행 할 수있는 도구를 생각할 수 없습니다 .

이 문제를 해결하려면 데코레이션-정렬-데코레이션을 수행해야합니다. 즉, 파일 이름을 가져 와서 처음에 필드 구분 기호를 입력 한 다음 정렬하고 첫 번째 열과 필드 구분 기호를 제거하십시오.

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

awk명령은 필드 구분 기호 FS/; 이것은 필드를 읽는 방식에 영향을줍니다. 출력 필드 분리가 OFS 또한 설정된다 /; 레코드를 인쇄하는 방식에 영향을줍니다. 다음 문장은 마지막 열 ( NF레코드의 필드 수이므로 마지막 필드의 인덱스이기도 함)과 전체 레코드 ( $0전체 레코드 임)를 인쇄합니다. 그들 사이에 OFS가 인쇄됩니다. 그런 다음 필드 구분 기호로 sort취급 되는 목록이 작성 /됩니다. 레코드에 파일 이름이 먼저 있기 때문에 그 순서대로 정렬됩니다. 그런 다음 cut필드 2부터 끝까지 만 필드를 인쇄 /하여 필드 구분 기호로 다시 처리 합니다.


3
이것은 find (1)과 함께 있기 때문에 awk 부분을 건너 뛰고 사용할 수 있습니다.-printf '%f/%p\n'
camh

실제로 설정이 약간 더 복잡합니다. 가변 하위 디렉토리 깊이를 포함합니다. 이 사실을 반영하기 위해 질문을 편집했습니다. 처음에는 이것을 포함하지 않은 것에 대해 사과드립니다.
unode

1
@Unode : Shawn의 솔루션은 가변 깊이를 잘 처리합니다.이 문제에 대한 정식 솔루션입니다 (사소한 변형까지).
Gilles 'SO- 악마 그만'

4

'-printf'파일을 사용하여 이름과 경로를 출력하고 이름별로 정렬하고 마지막 단계에서 이름을 잘라냅니다. '###'은 절단을 돕는 마커입니다.

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

% f는 파일 이름을 인쇄하고, 전체 경로의 % p를 인쇄합니다.

find 명령을 단순화하여 한 줄로 만들었습니다 ! -path "./build*". 물론 부품을 떠날 것 입니다.


3

zsh ≥4.3.10에서 :

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txt*.txt현재 디렉토리 및 해당 서브 디렉토리에서 재귀 적으로 일치 합니다 .
  • ~build* 텍스트가 build*(예 :)로 시작하는 일치 항목을 제외합니다! -path './build*' . ( setopt extended_glob먼저 필요합니다 .)
  • (oe\''…'\')정렬 glob 한정자 입니다. REPLY=…반환 할 문자열에서 정렬 할 문자열을 구성합니다.
  • ${REPLY:t}경로 의 기본 이름 ( "꼬리")입니다.

많은 연결된 마법. 흥미롭지 만 우리는 sh 구문으로 제한됩니다. +1
unode
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.