find -print0 재귀

find -print0 재귀

디렉터리와 하위 디렉터리의 모든 파일을 나열하고 배열에 저장한 다음 몇 가지 작업을 수행해야 합니다(기본적으로 배열에 대한 for 루프 및 속성 설정).

나는 다음과 같이 시작했습니다:

var=$(find ./ -type f)

내 문제는 파일 이름에 공백과 기타 친숙하지 않은 문자(내 잘못이 아닙니다!)가 포함되어 있어 문자열 배열(예: find 명령의 출력)을 구문 분석하는 것이 매우 복잡하다는 것입니다.

그래서 나는 내가 사용할 수 있다는 것을 알았습니다.찾기-print0재귀적이지 않은 것(하위 디렉터리가 아닌 디렉터리만)으로 나타나는 것을 제외하면 잘 작동합니다.

재귀적으로 보기 위해 전달할 수 있는 매개변수나 이에 상응하는 명령이 있습니까?

  • 디렉터리 및 하위 디렉터리의 모든 파일 나열
  • 목록을 문자열 배열로 저장하시겠습니까?

답변1

find항상 재귀적이지만 귀하의 것입니다.

var=$(find ./ -type f)

스칼라배열 변수 할당이 아닌 변수 할당입니다. $var마지막으로 문자열을 포함합니다: find개행 문자²를 포함한 전체 출력

bash 복사 zsh 구문에서 배열 변수 할당은 다음과 같습니다.

var=( 'first element' second-element etc... )

각 파일의 출력을 얻으려면 출력을 NUL 문자로 find -print0분할해야 합니다 . zsh에서는 매개변수 확장 플래그를 find사용할 수 있습니다 .0

var=( ${(0)"$(find . -type f -print0)"} )

Bash에는 이에 상응하는 것이 없으며 일반적으로 데이터 구조에 NUL을 저장할 수 없습니다. 그러나 버전 4.4부터 readarray프로세스 대체와 함께 내장 기능을 사용할 수 있습니다.

readarray -td '' var < <(find . -type f -print0)

readarrayfind각 레코드를 입력(여기서는 프로세스 대체를 통해 생성된 파이프)에 별도의 요소로 저장합니다. 를 사용하면 -d ''레코드 구분 기호는 개행 대신 NUL입니다. 사용하면 -t레코드 구분 기호가 제거됩니다. bash는 어쨌든 변수에 NUL을 저장할 수 없기 때문에 현재 버전의 bash에서는 필요하지 않지만 미래를 위해 추가했습니다.

요소를 반복하려면 다음을 수행하십시오.

for file in "${var[@]}"; do
  something with "$file"
done

여기서는 배열 사용을 건너뛰고 findwith의 출력에서 ​​직접 루프할 수도 있습니다.

while IFS= read -rd '' -u3 file; do
  something with "$file"
done 3< <(find . -type f -print0)

당신은 또한 볼 수 있습니다찾기 결과를 반복하는 것이 왜 나쁜 습관입니까?find일반적으로 발견되는 파일을 올바르게 루프하는 방법을 알아보세요.


-prune¹ 특정 디렉토리를 사용하거나 입력하지 말라고 명시적으로 지시하지 않거나 -xdev일부 find구현을 사용하여 깊이를 제한하지 않는 한 -maxdepth. 그러나 -L옵션이나 -follow조건자 4를 사용하지 않는 한 디렉토리에 대한 심볼릭 링크를 따르지 않습니다.

² 명령 대체에 의해 삭제된 후행 부분은 제외됩니다.

³ 음, 에서는 처음부터 비표준이 zsh필요하지 않습니다 . 단지 재귀 glob 및 glob 한정자를 사용하거나 심볼릭 링크를 따르기만 하면 됩니다.find-print0var=( **/*(ND.) )var=( ***/*(ND.) )

4그러나-L / -follow는 행동에도 영향을 미칠 수 있다는 점에 유의하십시오 -type. 일반 파일에 대한 기호 링크는 결국 여기에서 -type f선택됩니다 . GNU를 통해 구현되면 , 없이 일반 파일에 심볼릭 링크하는 대신 with를 find사용하여 일반 파일만 선택할 수 있습니다 .-xtype f-L-type f-L

답변2

실수를 했습니다. 소프트 링크를 사용하고 있었는데 사용하지 않았습니다.찾다그리고-엘배너.

original_list=()
while IFS= read -r -d $'\0'; do
    original_list+=("$REPLY")
done < <(find -L ./ -type f -print0)

작동합니다!

관련 정보