Intereting Posts
CentOS – проблема с правами на запись Symlink с одной рабочей станции на другую без монтирования Использование –exclude с командой du Как запустить перезагрузку в качестве обычного пользователя без необходимости вводить пароль? Есть ли способ сделать этот однострочный лайнер быстрее? В чем разница между устройством цикла и блочным устройством? Wi-Fi-карта, вызывающая высокие прерывания на Fedora 24 Как я могу подсчитать частоту строк среди многих файлов? Как узнать, когда закончится работа на экране? Что происходит с файлами в точке монтирования после запуска fs-cifs для монтирования NAS? Список установленных программ без запуска программы в системе Рассчитать и округлить числа в bash Текстовый файл, содержащий имена файлов и хешей – извлечение строк с повторяющимися хэшами Отключить настройку громкости выше 100% в pulseaudio Могу ли я узнать параметры автомонтирования?

Как мне перебирать только каталоги в bash?

У меня есть папка с некоторыми каталогами и некоторыми файлами (некоторые скрыты, начиная с точки).

for d in *; do echo $d done 

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

Вы можете указать косую черту в конце, чтобы соответствовать только каталогам:

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

Вы можете проверить с помощью -d :

 for f in *; do if [[ -d $f ]]; then # $f is a directory fi done 

Это один из операторов проверки файлов .

Вы можете использовать чистый bash для этого, но лучше использовать find:

 find . -maxdepth 1 -type d -exec echo {} \; 

(найти дополнительно будет включать скрытые каталоги)

Если вам нужно выбрать более конкретные файлы, чем только каталоги, используйте find и передайте его во while read :

 shopt -s dotglob find * -prune -type d | while IFS= read -rd; do echo "$d" done 

Используйте shopt -u dotglob чтобы исключить скрытые каталоги (или setopt dotglob / unsetopt dotglob в zsh).

IFS= чтобы избежать разбиения имен файлов, содержащих один из $IFS , например: 'a b'

см. AsymLabs ниже для получения дополнительных параметров find


редактировать:
Если вам нужно создать значение выхода из цикла while, вы можете обойти дополнительную подоболочку с помощью этого трюка:

 while IFS= read -rd; do if [ "$d" == "something" ]; then exit 1; fi done < <(find * -prune -type d) 

Помните, что решение choroba, хотя и изящно, может вызвать неожиданное поведение, если в текущем каталоге отсутствуют каталоги. В этом состоянии, а не пропускании цикла for , bash будет запускать цикл точно один раз, где d равно */ :

 #!/usr/bin/env bash for d in */; do # Will print */ if no directories are available echo $d done 

Я рекомендую использовать следующее для защиты от этого случая:

 #!/usr/bin/env bash for f in *; do if [ -d ${f} ]; then # Will not run if no directories are available echo $f fi done 

Этот код будет проходить через все файлы в текущем каталоге, проверьте, является ли f каталогом, а затем echo f если условие возвращает true. Если f равно */ , echo $f не будет выполняться.

Это делается для поиска как видимых, так и скрытых каталогов в текущем рабочем каталоге, за исключением корневого каталога:

просто прокрутить каталоги:

  find -path './*' -prune -type d 

включить символические ссылки в результат:

 find -L -path './*' -prune -type d 

делать что-то в каждом каталоге (исключая символические ссылки):

 find -path './*' -prune -type d -print0 | xargs -0 <cmds> 

для исключения скрытых каталогов:

 find -path './[^.]*' -prune -type d 

для выполнения нескольких команд по возвращаемым значениям (очень надуманный пример):

 find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \ "printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'" 

вместо «sh -c» также можно использовать «bash -c» и т. д.

Вы можете прокручивать все каталоги, включая скрытые каталоги (начиная с точки) в одной строке и несколько команд с помощью:

 for file in */ .*/ ; do echo "$file is a directory"; done 

Если вы хотите исключить символические ссылки:

 for file in *; do if [[ -d "$file" && ! -L "$file" ]]; then echo "$file is a directory"; fi; done 

примечание: использование списка */ .*/ работает в bash, но также отображает папки . и .. то время как в zsh он не будет показывать их, но выдает ошибку, если в папке нет скрытого файла

Чистая версия, которая будет включать скрытые каталоги и исключить ../, будет с опцией dotglob:

 shopt -s dotglob for file in */ ; do echo "$file is a directory"; done 

(или setopt dotglob в zsh)

вы можете отключить dotglob с помощью

 shopt -u dotglob 

Это будет включать полный путь в каждый каталог в списке:

 for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done 
 ls -d */ | while read d do echo $d done 

Используйте find с -exec для циклического -exec по каталогам и вызова функции в опции exec:

 dosomething () { echo "doing something with $1" } export -f dosomething find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \; 

Используйте shopt -s dotglob или shopt -u dotglob для включения / исключения скрытых каталогов

 ls -l | grep ^d 

или:

 ll | grep ^d 

Вы можете установить его как псевдоним