Во-первых, не делайте этого тот путь. Лучший подход должен использовать 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)
можно также заполнить массив от находки и передачу, которые выстраивают позже:
# 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
переменная, которая не содержит пробел. Выключите globbing (set -f
) для предотвращения строк, содержащих символы шарика такой как [1 112], *
или ?
от того, чтобы быть расширенным:
# this is unsafe (but less unsafe than it would be without the following precautions)
(
IFS= Наконец, для случая параметра командной строки, необходимо использовать массивы, если оболочка поддерживает их (т.е. это - ksh, удар или zsh):
# this is safe
for d in "$@"; do
printf '%s\n' "$d"
done
поддержит разделение. Обратите внимание, что заключение в кавычки (и использование [1 115], а не $*
) важно. Массивы могут быть заполнены другими способами также, такими как выражения шарика:
# this is safe
entries=( test/* )
for d in "${entries[@]}"; do
printf '%s\n' "$d"
done
\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, удар или zsh):
# this is safe
for d in "$@"; do
printf '%s\n' "$d"
done
поддержит разделение. Обратите внимание, что заключение в кавычки (и использование [1 115], а не $*
) важно. Массивы могут быть заполнены другими способами также, такими как выражения шарика:
# this is safe
entries=( test/* )
for d in "${entries[@]}"; do
printf '%s\n' "$d"
done
Добавить к какой сказанный Jonathan: используйте -print0
опция для find
в сочетании с xargs
следующим образом:
find test/* -type d -print0 | xargs -0 command
, Который выполнит команду command
с надлежащими аргументами; каталоги с пробелами в них будут правильно заключены в кавычки (т.е. они будут переданы в как один аргумент).
Это чрезвычайно хитро в стандартном Unix, и большинство решений ссорится с новыми строками или некоторым другим символом. Однако при использовании комплекта инструментальных средств GNU тогда можно использовать find
опция -print0
и использование xargs
с соответствующей опцией -0
(минус нуль). Существует два символа, которые не могут появиться в простом имени файла; те - наклонная черта и NUL '\0'. Очевидно, наклонная черта появляется в путях, таким образом, решение для GNU использования NUL '\0' для маркировки конца имени является оригинальным и надежным.
find . -type d | while read file; do echo $file; done
Однако не работает, если имя файла содержит новые строки. Вышеупомянутое является единственным решением, которое я знаю того, когда Вы на самом деле хотите иметь имя каталога в переменной. Если Вы просто хотите выполнить некоторую команду, используйте xargs.
find . -type d -print0 | xargs -0 echo 'The directory is: '
Не хранить списки в виде строк; храните их как массивы, чтобы избежать путаницы. Вот пример сценария, который будет работать либо со всеми подкаталогами test, либо со списком, предоставленным в его командной строке:
#!/bin/bash
if [ $# -eq 0 ]; then
# if no args supplies, build a list of subdirs of test/
dirlist=() # start with empty list
for f in test/*; do # for each item in test/ ...
if [ -d "$f" ]; then # if it's a subdir...
dirlist=("${dirlist[@]}" "$f") # add it to the list
fi
done
else
# if args were supplied, copy the list of args into dirlist
dirlist=("$@")
fi
# now loop through dirlist, operating on each one
for dir in "${dirlist[@]}"; do
printf "Directory: %s\n" "$dir"
done
Теперь давайте попробуем это на тестовом каталоге с добавленной кривой или двумя:
$ ls -F test
Baltimore/
Cherry Hill/
Edison/
New York City/
Philadelphia/
this is a dirname with quotes, lfs, escapes: "\''?'?\e\n\d/
this is a file, not a directory
$ ./test.sh
Directory: test/Baltimore
Directory: test/Cherry Hill
Directory: test/Edison
Directory: test/New York City
Directory: test/Philadelphia
Directory: test/this is a dirname with quotes, lfs, escapes: "\''
'
\e\n\d
$ ./test.sh "Cherry Hill" "New York City"
Directory: Cherry Hill
Directory: New York City
just found out there are some similarities between my question and yours. Aparrently if you want to pass arguments into commands
test.sh "Cherry Hill" "New York City"
to print them out in order
for SOME_ARG in "$@"
do
echo "$SOME_ARG";
done;
notice the $@ is surrounded by double quotes, some notes here
Также приходилось иметь дело с пробелами в именах путей. В конце концов я использовал рекурсию и для элемента в / path / *
:
function recursedir {
local item
for item in "${1%/}"/*
do
if [ -d "$item" ]
then
recursedir "$item"
else
command
fi
done
}
Вот простое решение, которое обрабатывает табуляции и / или пробелы в имени файла. Если вам приходится иметь дело с другими странными символами в имени файла, такими как новые строки, выберите другой ответ.
Тестовый каталог
ls -F test
Baltimore/ Cherry Hill/ Edison/ New York City/ Philadelphia/ cities.txt
Код для входа в каталоги
find test -type d | while read f ; do
echo "$f"
done
Имя файла должно быть заключено в кавычки ( "$ f "
), если используется в качестве аргумента. Без кавычек пробелы действуют как разделители аргументов, и вызываемой команде передается несколько аргументов.
И вывод:
test/Baltimore
test/Cherry Hill
test/Edison
test/New York City
test/Philadelphia
Просто возникла проблема простого варианта ... Преобразование файлов из типизированного .flv в .mp3 (зевок).
for file in read `find . *.flv`; do ffmpeg -i ${file} -acodec copy ${file}.mp3;done
рекурсивно найти все пользовательские флэш-файлы Macintosh и превратить их в аудио (копировать, без перекодирования) ... это похоже на while выше, отмечая, что чтение вместо просто «для файла в » ускользнет.