Я работаю над script, который должен выполнять действие в каждом подкаталоге определенной папки.
Каков наиболее эффективный способ написать это?
Я работаю над script, который должен выполнять действие в каждом подкаталоге определенной папки.
Каков наиболее эффективный способ написать это?
for D in `find . -type d`
do
//Do whatever you need with D
done
Версия, которая позволяет избежать создания подпроцесса:
for D in *; do
if [ -d "${D}" ]; then
echo "${D}" # your processing here
fi
done
Или, если ваше действие является одной командой, это более кратким:
for D in *; do [ -d "${D}" ] && my_command; done
Или еще более сжатая версия (thanks @enzotib). Обратите внимание, что в этой версии каждое значение D
будет иметь завершающую косую черту:
for D in */; do my_command; done
Самый простой нерекурсивный способ:
for d in */; do
echo "$d"
done
/
в конце говорит, используйте только каталоги.
Нет необходимости
find
.В GNU find
вы можете использовать параметр -execdir
:
find . -type d -execdir realpath "{}" ';'
или с помощью параметра -exec
:
find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;
или с помощью команды xargs
:
find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'
Или использовать для цикла:
for d in */; { echo "$d"; }
Для рекурсивности попробуйте расширенное globbing (**/
) вместо (enable by: shopt -s extglob
).
Дополнительные примеры см. в разделе Как перейти в каждый каталог и выполнить команду? в SO
Удобные однострочные
for D in *; do echo "$D"; done
for D in *; do find "$D" -type d; done ### Option A
find * -type d ### Option B
Вариант A правильный для папок с промежутками между ними. Кроме того, обычно быстрее, поскольку он не печатает каждое слово в имени папки как отдельный объект.
# Option A
$ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
real 0m0.327s
user 0m0.084s
sys 0m0.236s
# Option B
$ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
real 0m0.787s
user 0m0.484s
sys 0m0.308s
find . -type d -print0 | xargs -0 -n 1 my_command
Это создаст подоболочку (это означает, что значения переменной будут потеряны при выходе цикла while
):
find . -type d | while read -r dir
do
something
done
Это не будет:
while read -r dir
do
something
done < <(find . -type d)
Либо один будет работать, если в именах каталогов есть пробелы.
принятый ответ разбивается на пробелы, если имена каталогов имеют их, а предпочтительный синтаксис $()
для bash/ksh. Используйте опцию GNU find
-exec
с помощью +;
например
find .... -exec mycommand +;
#this is same as passing to xargs
или используйте цикл while
find .... | while read -r D
do
...
done
Вы можете попробовать:
#!/bin/bash
### $1 == the first args to this script
### usage: script.sh /path/to/dir/
for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
cd "$f"
<your job here>
done
или аналогичный...
Пояснение:
find . -maxdepth 1 -mindepth 1 -type d
:
Только найти каталоги с максимальной рекурсивной глубиной 1 (только подкаталоги $1) и минимальной глубиной 1 (исключает текущую папку .
)