큰따옴표로 묶인 인수는 특정 파일 이름을 반복할 때 파일 이름이 손상되는 것을 방지하지 않습니다.
$ mkdir temp
$ cd temp/
$ touch a\ b
$ for f in $(find .) ; do echo "$f" ; done
.
./a
b
답변1
이 지시문은 for f in $(find .)
요소 목록을 공백을 기준으로 반복하여 분할합니다. zsh와 같은 최신 쉘에서는확장 플래그로 사용할 수 있습니다.
for f in "${(@f)$(find .)}" ; do echo "$f" ; done
머물면 bash
우리가 이 문제를 해결할 수 있어요다른 질문에서 언급했듯이find
결과를 변수에 할당하는 동안 입력 구분 기호(요소를 구분하는 데 사용되는 문자)를 임시로 수정합니다 . 일시적으로 고빙을 비활성화하면 *
해당 문자 와 같은 와일드카드 문자의 확장이 방지됩니다 .
set -f # Disable globbing.
IFS=$(echo -e '\0') files=( $(find . -print0) ) # Read newline separated files into an array.
for f in ${files[@]}; do echo $f; done
set +f # Reenable globbing.
그러나 이것은 단지 문제를 변화시켰을 뿐이고, 이제 파일 이름에 개행 문자가 있으면 작동하지 않습니다. 아마도 모든 파일 시스템에서 금지되는 것 중 하나는 널 문자일 것입니다. 그러나 bash의 변수는 이를 보유하지 않을 수 있으므로 에 할당할 수 없습니다 IFS
.
find
또는 xargs를 사용하여 경로를 다른 프로그램 에 전달할 수 있습니다 . null 문자를 구분 기호로 사용하는 to -print0
명령을 사용 find
하고 -0
to로 전환합니다 . 한 번에 하나의 파일 이름을 처리하기 위해 호출 에 xargs
추가되었습니다 .-n1
xargs
find . -print0 | xargs -0 -n1 echo
답변2
인수의 변수 대체를 큰따옴표로 묶었 echo
지만 루프 반복 목록의 명령 대체는 큰따옴표로 묶지 않았습니다 for
. 여기서 공백과 기타 불쾌한 문제가 발생합니다.
find
개행 문자가 파일 이름의 일부인지 구분 기호의 일부인지 알 수 없기 때문에 출력을 구문 분석하는 완전히 신뢰할 수 있는 방법은 없습니다 .
find
파일 이름에 개행 문자가 포함되어 있지 않다고 가정할 수 있는 경우 \[?*
필드 구분 기호를 개행 문자로만 제한하고(공백과 탭 보호를 위해) 와일드카드를 꺼서(보호를 위해) 출력을 분할하도록 배열할 수 있습니다.
IFS='
'; set +f
for f in $(find .); do
unset IFS; set +f
echo "$f"
done
unset IFS; set +f
하지만 이를 수행하는 더 좋은 방법이 있습니다. 안정적으로 사용하는 가장 쉬운 방법 find
은 출력을 구문 분석하는 대신 명령을 실행하도록 하는 것입니다. 메타데이터가 아직 캐시에 있는 동안 파일이 처리될 가능성이 높으므로 속도가 더 빨라질 수도 있습니다.
find . -exec echo {} \;
쉘 명령이 필요한 경우 쉘을 명시적으로 호출하십시오. 인용에 주의하십시오. 파일 이름을 쉘에 인수로 전달하고, 쉘 명령에 삽입하려고 시도하지 마십시오.
find . -exec sh -c 'echo "$0"' {} \;
각 파일에 대해 셸 인스턴스를 호출하는 대신 셸 호출을 그룹화하고 여러 파일을 반복할 수 있습니다. 이 find
명령은 집계를 수행하고 명령줄 길이 제한이 초과되지 않도록 합니다. $0
파일 $1
등에 대한 더미 인수를 전달하는 것을 잊지 마십시오 .
find . -exec sh -c 'for x; do echo "$x"; done' _ {} +
ksh93, bash 또는 zsh를 사용하는 경우 재귀 와일드카드 기능을 사용할 수 있습니다. 즉, **/PATTERN
디렉터리와 해당 하위 디렉터리에서 와일드카드 패턴을 재귀적으로 검색합니다. ksh93에서는 먼저 실행해야 합니다 set -o globstar
. Bash에서는 shopt -s globstar
이를 먼저 실행 해야 하며 **
디렉터리의 심볼릭 링크 내에서도 반복된다는 점에 유의하세요.
for f in **/*; do
echo "$f"
done
Zsh도 있습니다글로벌 예선대부분의 용도에 적용됩니다 find
. 다른 껍질에는 이런 것이 없습니다.