cd во все каталоги, выполнить команду над файлами в этом каталоге и вернуться в предыдущий текущий каталог

Я пытаюсь написать сценарий, который будет запущен в заданном каталоге со многими одноуровневыми подкаталогами. Сценарий будет записываться в каждый из подкаталогов, выполнить команду в файлах в каталоге и вывести cd для продолжения в следующий каталог. Каков наилучший способ сделать это?

 for d in ./*/ ; do (cd "$d" && somecommand); done 

Лучший способ – не использовать cd вообще:

 find some/dir -type f -execdir somecommand {} \; 

execdir подобен exec , но рабочий каталог отличается:

  -execdir command {} [;|+] Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find. This a much more secure method for invoking commands, as it avoids race conditions during resolution of the paths to the matched files. 

Это не POSIX.

 cd -P . for dir in ./*/ do cd -P "$dir" ||continue printf %s\\n "$PWD" >&2 command && cd "$OLDPWD" || ! break; done || ! cd - >&2 

Вышеприведенная команда не нуждается в каких-либо подоболочках – она ​​просто отслеживает прогресс в текущей оболочке, чередуя $OLDPWD и $PWD . Когда вы cd - оболочка обменивает значение этих двух переменных, в основном, поскольку оно меняет каталоги. Он также печатает имя для каждого каталога, поскольку он работает там, в stderr.

Я просто второй раз посмотрел на него и решил, что смогу лучше справиться с обработкой ошибок. Он пропустит каталог, в который он не может cd – и cd выведет сообщение о том, почему в stderr – и он break w / ненулевой код выхода, если ваша command не будет выполнена успешно или если запущенная command каким-то образом повлияет на ее способность вернитесь в исходный каталог – $OLDPWD . В этом случае он также делает cd - last – и записывает полученное текущее имя рабочего каталога в stderr.

 pushd subdir # do stuff popd 

pushd / popd являются встроенными bash, которые предоставляют стек каталогов. Вы можете сделать несколько pushd s, затем несколько popd s и вернуться к тому, с чего вы начали. Вы также можете манипулировать стеком с помощью dirs .

Как встроенный bash, документация находится в man-файле bash ( man 1 bash и search ( / ) для pushd, n для продвижения вперед по результатам поиска) или используйте help pushd help popd help dirs .

 for D in ./*; do if [ -d "$D" ]; then cd "$D" run_something cd .. fi done