디렉토리의 파일을 반복적으로 반복


15

디렉토리에서 파일을 반복적으로 반복하는 것은 다음과 같이 쉽게 수행 할 수 있습니다.

find . -type f -exec bar {} \;

그러나 많은 조건부 분기, 반복 등을 수행 해야하는보다 복잡한 작업에는 위의 내용이 작동하지 않습니다. 나는 이것을 위의 용도로 사용했다.

while read line; do [...]; done < <(find . -type f)

그러나 문자가 모호한 파일에는 다음과 같이 작동하지 않는 것 같습니다.

$ touch $'a\nb'
$ find . -type f
./a?b

모호한 문자를 잘 처리하는 대안이 있습니까?


1
find ... -exec bash -c 'echo filename is in \$0: "$0"' {} \;더 좋은 방법입니다.
jw013

당신은이 문제를 해결하고 변경하여, 원래의 디자인을 유지할 수 read line에를 IFS= read -r line. 그것을 깨뜨릴 유일한 문자는 개행입니다.
Patrick

1
@Patrick이지만 파일 이름에는 줄 바꿈이 포함될 수 있습니다. 그것이 -d $'\0'바람직한 이유 입니다.
godlygeek

답변:


7

안전을find 위한 또 다른 용도 :

while IFS= read -r -d '' -u 9
do
    [Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )

(이것은 모든 POSIX와 함께 작동 find하지만 쉘 부분에는 bash가 필요합니다. * BSD와 GNU find를 사용하면 -print0대신 -exec printf '%s\0' {} +더 빠르게 사용할 수 있습니다.)

이를 통해 루프 내에서 표준 입력을 사용할 수 있으며 모든 경로에서 작동 합니다.


1
"읽기 ... 이름이 제공되지 않으면, 행 읽기는 변수 REPLY에 할당됩니다." 그래서do echo "Filename is '$REPLY'"
앤드류

9

이 작업은 다음과 같이 간단합니다.

find -exec sh -c 'inline script "$0"' {} \;

또는...

find -exec executable_script {} \;

5

가장 간단한 (아직 안전한) 접근 방식은 쉘 globbing을 사용하는 것입니다.

$ for f in *; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
h:

위의 재귀를 bash에서 하위 디렉토리로 만들려면 globstar옵션을 사용할 수 있습니다 . dotglob이름이 다음으로 시작하는 파일과 일치하도록 설정하십시오 ..

$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
:foo:
:foo/file1:
:foo/file two:
h:

bash 4.2 **/까지는 디렉토리에 대한 심볼릭 링크로 반복됩니다. bash 4.3 이후 **/와 같이 디렉토리에만 반복됩니다 find.

또 다른 일반적인 해결책은 다음 find -print0과 함께 사용하는 것 입니다 xargs -0.

$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e    f:
:./a b:
:./-e:
:./c
d:

(가) 있습니다 h:/g파일 이름이 포함되어 있으므로 실제로 올바른입니다 \r.


4

그것은 이식하여 읽기 루프를 수행하기 어려운 약간이지만, 특히 떠들썩한 파티를 위해 당신은 같은 것을 시도 할 수 있습니다 .

관련 부분 :

while IFS= read -d $'\0' -r file ; do
        printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)

findNUL 문자 (0x00)로 구분 된 출력을 인쇄하고 백 슬래시를 다른 문자 ( )의 이스케이프로 처리하지 않고 readNUL 구분 행 ( -d $'\0') 을 가져오고 행 ( )에서 -r단어를 나누지 않도록 지시 합니다 IFS=. 0x00은 Unix의 파일 이름 또는 경로에서 발생할 수없는 바이트이므로 모든 이상한 파일 이름 문제를 처리해야합니다.


1
-d ''와 같습니다 -d $'\0'.
l0b0 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.