이 질문은
왜 쉘 루프를 사용하여 텍스트를 처리하는 것이 나쁜 습관으로 간주됩니까?
나는이 구성들을 본다
for file in `find . -type f -name ...`; do smth with ${file}; done
과
for dir in $(find . -type d -name ...); do smth with ${dir}; done
… 거의 어떤 사람들은 이런 종류의 물건은 피해야한다 이유를 설명하는 소식에 댓글을 달 시간이 걸릴 경우에도 매일 여기에 사용되는
등 게시물의 수 (때로는 그 의견을 간단하게 무시하고 있다는 사실을)보고 나는 질문을 할 수도 있다고 생각했다.
루프 오버 find
출력이 나쁜 이유는 무엇이며 각 파일 이름 / 경로에 대해 하나 이상의 명령을 실행하는 올바른 방법은 find
무엇입니까?
답변
문제
for f in $(find .)
호환되지 않는 두 가지를 결합합니다.
find
줄 바꿈 문자로 구분 된 파일 경로 목록을 인쇄합니다. $(find .)
해당 목록에서 인용 부호 를 사용하지 않고 호출 할 때 호출되는 split + glob 연산자 는 문자를 $IFS
(기본적으로 줄 바꿈뿐만 아니라 공백 및 탭 (및 NUL in zsh
) 포함) 문자로 분할하고 각 결과 단어에 대해 globbing을 수행합니다 (제외 의 zsh
경우 ksh93 또는 pdksh 같은 파생 상품) (심지어 중괄호 확장!).
당신이 그것을 만들더라도 :
IFS='
' # split on newline only
set -o noglob # disable glob (also disables brace expansion in pdksh
# but not ksh93)
for f in $(find .) # invoke split+glob
줄 바꿈 문자가 파일 경로에서와 마찬가지로 유효하기 때문에 여전히 잘못되었습니다. 출력 find -print
은 단순히 후 처리가 가능하지 않습니다 ( 여기에 표시된 것처럼 복잡한 트릭을 사용하는 것을 제외하고 ).
즉, 쉘 find
은 파일의 루프를 시작하기 전에 출력을 완전히 저장 한 다음 분할 하여 출력 (메모리에 해당 출력을 두 번째로 저장함을 의미 함)해야합니다.
참고 find . | xargs cmd
유사한 문제가 (이, 공백, 줄 바꿈, 따옴표, (그리고 일부 큰 따옴표와 백 슬래시 xarg
구현) 유효한 문자의 일부가 형성되지 바이트는 문제가 있습니다)
더 정확한 대안
for
출력 에서 루프 를 사용하는 유일한 방법 find
은 다음을 zsh
지원 IFS=$'\0'
하고 사용 하는 것입니다 .
IFS=$'\0'
for f in $(find . -print0)
(교체 -print0
에 -exec printf '%s\0' {} +
대한 find
비 – 표준 (그러나 매우 일반적 요즘)을 지원하지 않는 구현 -print0
)를.
여기에 정확하고 이식 가능한 방법은 다음을 사용하는 것입니다 -exec
.
find . -exec something with {} \;
또는 something
둘 이상의 인수를 취할 수있는 경우 :
find . -exec something with {} +
셸에서 해당 파일 목록을 처리해야하는 경우 :
find . -exec sh -c '
for file do
something < "$file"
done' find-sh {} +
(하나 이상 시작될 수 있음 sh
).
일부 시스템에서는 다음을 사용할 수 있습니다.
find . -print0 | xargs -r0 something with
표준 구문에 비해 이점이 거의없고 파이프 또는 파이프 something
라는 의미 입니다.stdin
/dev/null
병렬 처리 -P
에 GNU 옵션 을 사용하는 것이 좋을 수도 있습니다 xargs
. stdin
문제는 GNU으로 해결할 수 있습니다 xargs
와 -a
공정 대체를 지원 껍질 옵션 :
xargs -r0n 20 -P 4 -a <(find . -print0) something
예를 들어, something
각각 20 개의 파일 인수 를 갖는 최대 4 개의 동시 호출을 실행합니다 .
함께 zsh
또는 bash
의 출력을 반복 할 다른 방법 find -print0
에있다 :
while IFS= read -rd '' file <&3; do
something "$file" 3<&-
done 3< <(find . -print0)
read -d ''
개행으로 구분 된 레코드 대신 NUL로 구분 된 레코드를 읽습니다.
bash-4.4
이상은 다음을 사용 find -print0
하여 반환 된 파일을 배열에 저장할 수도 있습니다 .
readarray -td '' files < <(find . -print0)
zsh
(보존하는 장점이있다 상당 find
의 종료 상태) :
files=(${(0)"$(find . -print0)"})
을 사용하면 zsh
대부분의 find
표현식을 재귀 globbing과 glob 한정자 조합으로 변환 할 수 있습니다 . 예를 들어, 반복 find . -name '*.txt' -type f -mtime -1
은 다음과 같습니다.
for file (./**/*.txt(ND.m-1)) cmd $file
또는
for file (**/*.txt(ND.m-1)) cmd -- $file
(의 필요 조심 --
와 마찬가지로 **/*
, 파일 경로로 시작하지 않는 ./
, 그래서 시작 할 수 있습니다 -
예를 들어).
ksh93
그리고 bash
결국에 대한 지원을 추가 **/
여전히 있지만 사용하게 글로브 예선 (안 더 발전 재귀 대체 (globbing)의 형태하지만) **
매우가 제한합니다. 또한 bash
4.3 이전 버전에서는 디렉토리 트리를 내릴 때 심볼릭 링크를 따릅니다.
루핑 오버와 마찬가지로 $(find .)
이는 전체 파일 목록을 메모리 1 에 저장하는 것을 의미합니다 . 파일에 대한 작업이 파일 검색 에 영향을 미치지 않게하려는 경우 (예를 들어, 파일 자체를 찾을 수있는 파일을 더 추가 할 때)에는 바람직 할 수 있습니다.
다른 안정성 / 보안 고려 사항
경쟁 조건
이제 신뢰성에 대해 이야기하고 있다면, 시간 find
/ zsh
파일 찾기 사이의 경쟁 조건을 언급하고 파일이 기준과 사용 시간을 충족하는지 확인합니다 ( TOCTOU race ).
디렉토리 트리를 내릴 때도 심볼릭 링크를 따르지 말고 TOCTOU 레이스없이 수행해야합니다. find
( find
적어도 GNU )는 openat()
올바른 O_NOFOLLOW
플래그 (지원되는 경우)를 사용하여 디렉토리를 열고 각 디렉토리에 대해 파일 디스크립터를 열어 두어 zsh
/ bash
/ ksh
하지 마십시오. 따라서 공격자가 적시에 디렉토리를 심볼릭 링크로 교체 할 수있게되면 잘못된 디렉토리를 내릴 수 있습니다.
심지어 경우 find
에, 제대로 디렉토리를 내려하지 -exec cmd {} \;
더욱 더와 -exec cmd {} +
한 번 cmd
같은 예를 들어, 실행 cmd ./foo/bar
또는 cmd ./foo/bar ./foo/bar/baz
시간으로 cmd
사용한다 ./foo/bar
의 속성, bar
더 이상 일치 기준에 부합하지 않을 수 find
있지만, 더 악화가 ./foo
되었을 수도 있습니다 다른 곳으로 심볼릭 링크로 대체 (그리고 경주 창에 더 큰 많이 만든 -exec {} +
곳 find
호출 할 수있는 충분한 파일을 가지고 대기를 cmd
).
일부 find
구현에는 -execdir
두 번째 문제점을 완화하기 위해 ( 비표준이지만) 술어가 있습니다.
와:
find . -execdir cmd -- {} \;
find
chdir()
실행하기 전에 파일의 상위 디렉토리로 cmd
. 을 호출하는 대신 ( 일부 구현에서는)을 cmd -- ./foo/bar
호출 하므로 심볼릭 링크로 변경되는 문제를 피할 수 있습니다. 이렇게하면 더 안전한 명령을 사용하게 되지만 (다른 파일을 제거 할 수는 있지만 다른 디렉토리의 파일은 제거 할 수는 없음) 심볼릭 링크를 따르지 않도록 설계되지 않은 경우 파일을 수정할 수있는 명령은 사용할 수 없습니다.cmd -- ./bar
cmd -- bar
--
./foo
rm
-execdir cmd -- {} +
때때로 GNU의 일부 버전을 포함하여 여러 구현과 작동하지만 find
, 그것은 동일합니다 -execdir cmd -- {} \;
.
-execdir
너무 깊은 디렉토리 트리와 관련된 일부 문제를 해결하는 이점도 있습니다.
에서:
find . -exec cmd {} \;
주어진 경로의 크기는 cmd
파일이있는 디렉토리의 깊이에 따라 커질 것입니다. 크기가 PATH_MAX
Linux 보다 4k 보다 크면 cmd
해당 경로에서 수행되는 모든 시스템 호출 은 오류와 함께 실패 ENAMETOOLONG
합니다.
을 사용 -execdir
하면 파일 이름 만 접두사로 붙일 ./
수 cmd
있습니다. 대부분의 파일 시스템에서 파일 이름 자체는보다 훨씬 낮은 한계 ( NAME_MAX
) PATH_MAX
를 가지므로 ENAMETOOLONG
오류가 발생할 가능성이 적습니다.
바이트 대 문자
또한 find
일반적으로 파일 이름을 처리 할 때 보안을 고려할 때 간과되는 경우가 많습니다 . 대부분의 유닉스 계열 시스템에서 파일 이름은 바이트 시퀀스 (파일 경로에서는 0이지만 모든 파일 시스템에서는 0 임) ASCII 기반의 경우, 지금은 희귀 한 EBCDIC 기반의 것을 무시합니다. 0x2f는 경로 구분 기호입니다).
해당 바이트를 텍스트로 간주할지 여부는 응용 프로그램에 따라 다릅니다. 그리고 일반적으로 그렇게하지만 일반적으로 바이트에서 문자로의 변환은 환경에 따라 사용자의 로캘을 기반으로 수행됩니다.
그 의미는 주어진 파일 이름이 로케일에 따라 다른 텍스트 표현을 가질 수 있다는 것입니다. 예를 들어, 바이트 시퀀스 63 f4 74 e9 2e 74 78 74
는 côté.txt
문자 세트가 ISO-8859-1 인 cєtщ.txt
로케일과 문자 세트가 IS0-8859-5 인 로케일에서 해당 파일 이름을 해석하는 응용 프로그램을위한 것입니다.
보다 나쁜. 문자 집합이 UTF-8 (현재 표준) 인 로케일에서 63 f4 74 e9 2e 74 78 74는 단순히 문자에 맵핑 될 수 없습니다!
find
파일 이름을 -name
/ -path
술어에 대한 텍스트로 간주하는 응용 프로그램 중 하나입니다 (그리고 더, -iname
또는 -regex
일부 구현과 함께).
그 의미는 예를 들어 여러 find
구현 (GNU 포함 find
) 을 사용한다는 것입니다 .
find . -name '*.txt'
63 f4 74 e9 2e 74 78 74
UTF-8 로켈에서 호출 할 때 위 의 파일을 찾을 수 없으므로 (바이트가 아닌 *
0 개 이상의 문자 와 일치) 해당 문자가 아닌 문자와 일치 할 수 없습니다.
LC_ALL=C find...
C 로케일은 문자 당 1 바이트를 의미하고 (일반적으로) 모든 바이트 값이 문자에 매핑되도록 보장하기 때문에 (일부 바이트 값에 대해서는 정의되지 않은 것이더라도) 문제를 해결합니다.
이제 쉘에서 해당 파일 이름을 반복 할 때 해당 바이트 대 문자도 문제가 될 수 있습니다. 우리는 일반적으로 다음과 같은 4 가지 주요 유형의 쉘을 봅니다.
-
여전히 멀티 바이트를 인식하지 못하는 것들은
dash
. 그들을 위해 바이트는 문자에 매핑됩니다. 예를 들어, UTF-8에서côté
4 자이지만 6 바이트입니다. UTF-8이 문자 세트 인 로케일에서find . -name '????' -exec dash -c ' name=${1##*/}; echo "${#name}"' sh {} \;
find
UTF-8로 인코딩 된 4 개의 문자로 구성된 파일을 성공적으로 찾을 수 있지만dash
길이는 4에서 24 사이입니다. -
yash
: 반대. 문자 만 다룹니다 . 모든 입력은 내부적으로 문자로 변환됩니다. 가장 일관된 쉘을 만들지 만 임의의 바이트 시퀀스 (유효한 문자로 변환되지 않는)에 대처할 수 없다는 것을 의미합니다. C 로케일에서도 0x7f 이상의 바이트 값에는 대처할 수 없습니다.find . -exec yash -c 'echo "$1"' sh {} \;
예를 들어 UTF-8 로켈의 ISO-8859-1에서는 실패
côté.txt
합니다. -
멀티 바이트 지원이 좋아
bash
지거나zsh
점진적으로 추가 된 것들. 그것들은 마치 문자 인 것처럼 문자에 매핑 될 수없는 바이트를 고려하는 것으로 넘어갑니다. 여기에는 여전히 몇 가지 버그가 있으며 특히 GBK 또는 BIG5-HKSCS와 같은 덜 일반적인 멀티 바이트 문자 세트가 있습니다 (멀티 바이트 문자 중 많은 수가 0-127 범위의 바이트를 포함하므로 상당히 불쾌합니다 (ASCII 문자와 같은)). ). -
sh
FreeBSD 와 같 거나 (최소 11 개)mksh -o utf8-mode
멀티 바이트를 지원하지만 UTF-8 만 지원합니다.
노트
1 완전성을 zsh
위해 전체 목록을 메모리에 저장하지 않고 재귀 적 globbing을 사용하여 파일을 반복 하는 해킹 방법을 언급 할 수 있습니다 .
process() {
something with $REPLY
false
}
: **/*(ND.m-1+process)
+cmd
은 cmd
현재 파일 경로를 사용하여 (일반적으로 함수) 를 호출하는 glob 한정자입니다 $REPLY
. 이 함수는 파일을 선택해야하는지 여부를 결정하기 위해 true 또는 false를 반환합니다 (또한 $REPLY
여러 파일을 $reply
배열 로 수정 하거나 반환 할 수도 있음 ). 여기서 우리는 그 함수에서 처리하고 파일을 선택하지 않도록 false를 반환합니다.
답변
루프 오버
find
출력 이 왜 나쁜 습관입니까?
간단한 대답은 다음과 같습니다.
파일 이름은 모든 문자를 포함 할 수 있기 때문 입니다.
따라서 파일 이름을 구분하는 데 안정적으로 사용할 수있는 인쇄 가능한 문자가 없습니다.
뉴 라인이되어 종종 이 있기 때문에, 파일 이름을 구분하기 위해 (잘못) 사용 이상한 파일 이름에서 개행 문자를 포함 할 수 있습니다.
그러나 임의의 가정을 중심으로 소프트웨어를 구축하는 경우에는 예외적 인 경우를 처리하지 못하고 최악의 경우 시스템을 제어 할 수있는 악의적 인 악용에 노출 될 수 있습니다. 따라서 견고성과 안전의 문제입니다.
두 가지 방식으로 소프트웨어를 작성할 수 있고 그 중 하나가 엣지 케이스 (비정상 입력)를 올바르게 처리하지만 다른 하나는 읽기가 더 쉬운 경우, 트레이드 오프가 있다고 주장 할 수 있습니다. (그렇지 않습니다. 올바른 코드를 선호합니다.)
그러나, 정확하고 강력한 코드 버전 도 읽기 쉬운 경우, 에지 사례에서 실패한 코드 작성에 대한 변명의 여지가 없습니다. 이 경우 find
발견 된 각 파일에 대해 명령을 실행해야합니다.
좀 더 구체적으로 설명하자면 : UNIX 또는 Linux 시스템에서 파일 이름에는 /
경로 구성 요소 구분자로 사용되는 문자를 제외한 모든 문자가 포함될 수 있으며 null 바이트를 포함 할 수 없습니다.
따라서 널 바이트는 파일 이름을 구분 하는 유일한 올바른 방법입니다.
GNU 이후 find
포함 -print0
가 인쇄 파일명을 구분하기 위해 널 (null) 바이트를 사용 차를 GNU가 find
있다 안전하게 GNU 함께 사용 xargs
및 -0
플래그 (및 -r
출력을 처리하는 플래그) find
:
find ... -print0 | xargs -r0 ...
그러나이 양식을 사용해야 할 이유 는 없습니다 .
- GNU findutils에 대한 의존성을 추가합니다.
find
되어 설계 찾은 파일에서 명령을 실행할 수 있도록.
또한, GNU는 xargs
필요 -0
와 -r
FreeBSD는 반면, xargs
단지 필요 -0
(더없는 -r
옵션), 일부는 xargs
지원하지 않습니다 -0
전혀. 따라서 POSIX 기능 find
(다음 섹션 참조)을 고수 하고 건너 뛰는 것이 가장 좋습니다 xargs
.
find
발견 한 파일에 대해 명령을 실행할 수있는 지점 2 와 관련하여 Mike Loukides는 다음과 같이 말했습니다.
find
의 사업은 파일을 찾는 것이 아니라 표현을 평가하는 것입니다. 예,find
확실히 파일을 찾습니다. 그러나 그것은 실제로 부작용 일뿐입니다.
POSIX 지정 용도 find
각
find
결과 에 대해 하나 이상의 명령을 실행하는 올바른 방법은 무엇입니까 ?
발견 된 각 파일에 대해 단일 명령을 실행하려면 다음을 사용하십시오.
find dirname ... -exec somecommand {} \;
발견 된 각 파일에 대해 여러 명령을 순서대로 실행하려면 첫 번째 명령이 성공한 경우에만 두 번째 명령을 실행해야합니다.
find dirname ... -exec somecommand {} \; -exec someothercommand {} \;
한 번에 여러 파일에서 단일 명령을 실행하려면
find dirname ... -exec somecommand {} +
find
와 함께 sh
당신이 사용해야하는 경우 쉘 과 같은 출력을 재 지정하거나 파일 이름이나 비슷한 해제 확장을 제거 등의 명령에 기능을, 당신은 사용할 수 있습니다 sh -c
구조를. 이것에 대해 몇 가지를 알아야합니다.
-
코드에
{}
직접 포함 하지 마십시오sh
. 이를 통해 악의적으로 제작 된 파일 이름에서 임의의 코드를 실행할 수 있습니다. 또한 실제로 POSIX에 의해 지정되지 않았으므로 전혀 작동하지 않습니다. (다음 요점 참조) -
{}
여러 번 사용하거나 더 긴 인수의 일부로 사용 하지 마십시오 . 이것은 휴대용이 아닙니다. 예를 들어, 이렇게하지 마십시오 :find ... -exec cp {} somedir/{}.bak \;
POSIX 사양
find
을 인용하려면 :경우 UTILITY_NAME 또는 인수 문자열이 두 글자 “{}”하지만 단지 두 개의 문자가 포함 된 “{}”, 그것을 구현 한 것인지의 여부입니다 발견이 두 문자를 대체하거나 변경하지 않고 문자열을 사용합니다.
… 두 문자 “{}”을 (를) 포함하는 인수가 둘 이상 있으면 동작이 지정되지 않습니다.
-
-c
옵션으로 전달 된 쉘 명령 문자열 다음의 인수 는로 시작$0
하여 쉘의 위치 매개 변수로 설정됩니다 . 로 시작하지 않습니다$1
.이러한 이유로 생성 된 쉘 내에서 오류보고에 사용될 “더미”
$0
값 을 포함하는 것이 좋습니다find-sh
. 또한"$@"
여러 파일을 셸에 전달할 때 와 같은 구문을 사용할 수 있지만 값을 생략하면$0
전달 된 첫 번째 파일이로 설정$0
되어 포함되지 않습니다"$@"
.
파일 당 단일 쉘 명령을 실행하려면 다음을 사용하십시오.
find dirname ... -exec sh -c 'somecommandwith "$1"' find-sh {} \;
그러나 일반적으로 발견 된 모든 단일 파일에 대해 쉘을 생성하지 않도록 쉘 루프에서 파일을 처리하는 성능이 향상됩니다.
find dirname ... -exec sh -c 'for f do somecommandwith "$f"; done' find-sh {} +
( for f do
이는 for f in "$@"; do
각 위치 매개 변수와 동일 하고 처리합니다. 즉, find
이름의 특수 문자에 관계없이로 찾은 각 파일을 사용 합니다.)
올바른 find
사용법 의 추가 예 :
(참고 :이 목록을 자유롭게 확장하십시오.)
답변
이 답변은 매우 큰 결과 집합에 대한 것이며 주로 느린 네트워크를 통해 파일 목록을 가져올 때의 성능과 관련이 있습니다. 소량의 파일 (예 : 로컬 디스크에서 몇 100 또는 1000 정도)의 경우 대부분이 문제가됩니다.
병렬 처리 및 메모리 사용량
분리 문제와 관련하여 주어진 다른 답변 외에도 다른 문제가 있습니다.
for file in `find . -type f -name ...`; do smth with ${file}; done
줄 바꿈으로 분할되기 전에 백틱 내부의 부분을 먼저 완전히 평가해야합니다. 즉, 대량의 파일을 얻는 경우 다양한 구성 요소에있는 크기 제한에 질식 할 수 있습니다. 제한이 없으면 메모리가 부족할 수 있습니다. 어쨌든 전체 목록이 출력 될 때까지 기다렸다가 첫 번째 find
구문을 for
실행하기 전에 구문 분석 해야합니다 smth
.
선호되는 유닉스 방식은 본질적으로 병렬로 실행되며 일반적으로 임의로 큰 버퍼가 필요하지 않은 파이프를 사용하는 것입니다. 즉, find
를 병렬로 실행 하는 것을 훨씬 선호 smth
하며 현재 파일 이름을 RAM에 유지하면서 파일 이름을 RAM에 보관하십시오 smth
.
이를위한 적어도 부분적으로 OKish 솔루션은 앞서 언급 한 것 find -exec smth
입니다. 모든 파일 이름을 메모리에 유지할 필요가 없으며 병렬로 훌륭하게 실행됩니다. 불행히도 smth
파일 당 하나의 프로세스를 시작 합니다. smth
하나의 파일에서만 작동 할 수 있다면 그렇게해야합니다.
가능하다면, 최적의 솔루션이 될 것 find -print0 | smth
으로, smth
자사의 STDIN에 파일 이름을 처리 할 수있는. 그런 다음 smth
파일 수에 관계없이 하나의 프로세스 만 있으며 두 프로세스간에 적은 양의 바이트 (내재적 파이프 버퍼링이 진행중인 경우) 만 버퍼링해야합니다. 물론 이것은 smth
표준 Unix / POSIX 명령 이라면 다소 비현실적 이지만 직접 작성하는 경우 접근 방법이 될 수 있습니다.
이것이 가능하지 않다면 find -print0 | xargs -0 smth
아마도 더 나은 해결책 중 하나 일 것입니다. 주석에서 언급 한 @ dave_thompson_085 는 시스템 한계에 도달 할 때 (기본적으로 128KB 범위 또는 시스템에 부과되는 한계 에 따라) xargs
여러 실행으로 인수를 나눕니다. 파일은 한 번의 호출로 주어 지므로 프로세스 수와 초기 지연 간의 균형을 찾습니다 .smth
exec
smth
smth
편집 : “최고”의 개념을 제거-더 나은 무언가가자를 지 여부를 말하기 어렵습니다. 😉
답변
한 가지 이유는 공백이 작업에서 스패너를 던지고 ‘foo bar’파일이 ‘foo’및 ‘bar’로 평가되게하기 때문입니다.
$ ls -l
-rw-rw-r-- 1 ec2-user ec2-user 0 Nov 7 18:24 foo bar
$ for file in `find . -type f` ; do echo filename $file ; done
filename ./foo
filename bar
$
-exec를 대신 사용하면 정상적으로 작동합니다.
$ find . -type f -exec echo filename {} \;
filename ./foo bar
$ find . -type f -exec stat {} \;
File: ‘./foo bar’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: ca01h/51713d Inode: 9109 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 500/ec2-user) Gid: ( 500/ec2-user)
Access: 2016-11-07 18:24:42.027554752 +0000
Modify: 2016-11-07 18:24:42.027554752 +0000
Change: 2016-11-07 18:24:42.027554752 +0000
Birth: -
$
답변
모든 명령의 출력은 단일 문자열이지만 루프를 반복하려면 루프에 문자열 배열이 필요합니다. “작동”하는 이유는 쉘이 문자열을 배신하여 공백으로 나눕니다.
둘째,의 특정 기능이 필요하지 않은 경우 find
, 쉘이 이미 재귀 glob 패턴을 자체적으로 확장 할 수 있으며 결정적으로 적절한 배열로 확장 될 수 있다는 점에 유의하십시오.
배쉬 예제 :
shopt -s nullglob globstar
for i in **
do
echo «"$i"»
done
물고기도 마찬가지입니다 :
for i in **
echo «$i»
end
의 기능이 필요한 경우 관용구 find
와 같이 NUL에서만 분할해야합니다 find -print0 | xargs -r0
.
물고기는 NUL 구분 출력을 반복 할 수 있습니다. 그래서이 사람은 실제로 하지 나쁜 :
find -print0 | while read -z i
echo «$i»
end
마지막으로, 많은 쉘 (물론 피쉬가 아닌)에서 명령 출력을 반복하면 루프 본문이 하위 쉘이됩니다 (루프가 끝난 후에 볼 수있는 방식으로 변수를 설정할 수 없음을 의미 함). 당신이 원하는 것을 절대로.
답변
find의 출력을 반복하는 것은 나쁜 습관이 아닙니다. 나쁜 습관 (이 상황 및 모든 상황에서)은 입력이 특정 형식 인지 알기 (테스트 및 확인) 대신 특정 형식 이라고 가정 합니다 .
tldr / cbf : find | parallel stuff