Выполните действие в каждом подкаталоге, используя Bash - PullRequest
166 голосов
/ 23 октября 2010

Я работаю над сценарием, который должен выполнить действие в каждом подкаталоге определенной папки.

Какой самый эффективный способ написать это?

Ответы [ 9 ]

253 голосов
/ 23 октября 2010

Версия, которая избегает создания подпроцесса:

for D in *; do
    if [ -d "${D}" ]; then
        echo "${D}"   # your processing here
    fi
done

Или, если ваше действие - одна команда, это более кратко:

for D in *; do [ -d "${D}" ] && my_command; done

Или еще болеекраткая версия ( спасибо @ enzotib ).Обратите внимание, что в этой версии каждое значение D будет иметь косую черту:

for D in */; do my_command; done
159 голосов
/ 23 октября 2010
for D in `find . -type d`
do
    //Do whatever you need with D
done
86 голосов
/ 14 ноября 2016

Простейший нерекурсивный способ:

for d in */; do
    echo "$d"
done

В конце / говорит, использовать только каталоги.нужно для

  • найти
  • awk
  • ...
14 голосов
/ 12 сентября 2015

Используйте команду 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'

Или используя для loop:

for d in */; { echo "$d"; }

Для рекурсивности вместо этого попробуйте использовать расширенную глобализацию (**/) (включите: shopt -s extglob).


Дополнительные примеры см .: Как перейти в каждый каталог и выполнить команду? при SO

12 голосов
/ 20 марта 2014

Удобные однострочные

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
9 голосов
/ 23 октября 2010

find . -type d -print0 | xargs -0 -n 1 my_command

7 голосов
/ 23 октября 2010

Это создаст подоболочку (что означает, что значения переменных будут потеряны при выходе из цикла while):

find . -type d | while read -r dir
do
    something
done

Это не будет:

while read -r dir
do
    something
done < <(find . -type d)

Либоодин будет работать, если в именах каталогов есть пробелы.

5 голосов
/ 20 апреля 2016

Вы можете попробовать:

#!/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 (исключая текущую папку .)

4 голосов
/ 23 октября 2010

принятый ответ будет разбит на пробелы, если имена каталогов имеют их, и предпочтительный синтаксис для bash / ksh - $(). Используйте опцию GNU find -exec с +; например

find .... -exec mycommand +; #this is same as passing to xargs

или используйте цикл while

find .... |  while read -r D
do
  ...
done 
...