Во-первых, не делай так. Наилучший подход - правильно использовать find -exec
:
# this is safe
find test -type d -exec echo '{}' +
Другим безопасным подходом является использование списка, заканчивающегося NUL, хотя для этого требуется, чтобы ваша поддержка поиска поддерживала -print0
:
# this is safe
while IFS= read -r -d '' n; do
printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d -print0)
Вы также можете заполнить массив из find и передать этот массив позже:
# this is safe
declare -a myarray
while IFS= read -r -d '' n; do
myarray+=( "$n" )
done < <(find test -mindepth 1 -type d -print0)
printf '%q\n' "${myarray[@]}" # printf is an example; use it however you want
Если ваша находка не поддерживает -print0
, тогда ваш результат небезопасен - приведенные ниже данные не будут вести себя так, как требуется, если существуют файлы, содержащие в своих именах новые строки (что, да, допустимо):
# this is unsafe
while IFS= read -r n; do
printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d)
Если кто-то не собирается использовать один из вышеперечисленных, третий подход (менее эффективный с точки зрения использования времени и памяти, так как он читает весь вывод подпроцесса перед делением слов), заключается в использовании IFS
переменная, которая не содержит пробела. Отключите глобализацию (set -f
), чтобы предотвратить расширение строк, содержащих символы глобуса, такие как []
, *
или ?
:
# this is unsafe (but less unsafe than it would be without the following precautions)
(
IFS=$'\n' # split only on newlines
set -f # disable globbing
for n in $(find test -mindepth 1 -type d); do
printf '%q\n' "$n"
done
)
Наконец, для случая параметра командной строки вы должны использовать массивы, если ваша оболочка поддерживает их (то есть это ksh, bash или zsh):
# this is safe
for d in "$@"; do
printf '%s\n' "$d"
done
будет поддерживать разделение. Обратите внимание, что цитирование (и использование $@
вместо $*
) важно. Массивы могут быть заполнены и другими способами, такими как выражения glob:
# this is safe
entries=( test/* )
for d in "${entries[@]}"; do
printf '%s\n' "$d"
done