Как перебрать каталоги в Linux? - PullRequest
140 голосов
/ 21 января 2010

Я пишу скрипт на bash для Linux и мне нужно пройти через все имена подкаталогов в данном каталоге. Как я могу просмотреть эти каталоги (и пропустить обычные файлы)?

Например:
данный каталог /tmp/
он имеет следующие подкаталоги: /tmp/A, /tmp/B, /tmp/C

Я хочу получить A, B, C.

Ответы [ 8 ]

391 голосов
/ 21 января 2010

Все ответы на данный момент используют find, так что вот только с оболочкой. Нет необходимости во внешних инструментах в вашем случае:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo ${dir##*/}    # print everything after the final "/"
done
116 голосов
/ 21 января 2010
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

Краткое объяснение: find находит файлы (вполне очевидно)

  • . это текущий каталог, после компакт-диска это /tmp (ИМХО это более гибко, чем наличие /tmp непосредственно в команде поиска. У вас есть только одно место, cd, для изменения, если вы хотите выполнить больше действий место в этой папке)

  • -maxdepth 1 и -mindepth 1 убедитесь, что find действительно, только смотрит в текущем каталоге и не включает в себя '.' в результате

  • -type d ищет только каталоги

  • -printf '%f\n печатает только имя найденной папки (плюс символ новой строки) для каждого нажатия.

E вуаля!

39 голосов
/ 21 октября 2013

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

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

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


Другая возможность для bash включить скрытые каталоги:

shopt -s dotglob;
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

Чтобы вывести только конечное имя каталога (A, B, C, как опрошено) в каждом решении, используйте это в циклах:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"

Пример (это также работает с каталогами, которые содержат пробелы):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done
14 голосов
/ 08 октября 2012

Работает с каталогами, которые содержат пробелы

Вдохновлен Sorpigal

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

Оригинальный пост (не работает с пробелами)

Вдохновлен Болдевин : Пример цикла с командой find.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done
7 голосов
/ 21 января 2010
find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"
5 голосов
/ 25 сентября 2014

Чаще всего я использую технику find | xargs. Например, если вы хотите сделать каждый файл в этом каталоге и все его подкаталоги доступными для чтения, вы можете сделать:

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx

Параметр -print0 оканчивается символом NULL вместо пробела. Опция -0 разделяет входные данные таким же образом. Так что это комбинация для использования с файлами с пробелами.

Вы можете изобразить эту цепочку команд как вывод каждой строки с помощью find и прикрепление ее к концу команды chmod.

Если команда, которую вы хотите запустить в качестве аргумента в середине, а не в конце, вы должны быть немного изобретательны. Например, мне нужно было перейти в каждый подкаталог и запустить команду latemk -c. Поэтому я использовал (из Википедия ):

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord

Это имеет эффект for dir $(subdirs); do stuff; done, но безопасно для каталогов с пробелами в их именах. Кроме того, отдельные вызовы stuff выполняются в одной и той же оболочке, поэтому в моей команде мы должны вернуться к текущему каталогу с popd.

2 голосов
/ 11 июня 2018

минимальный цикл bash, из которого вы можете построить (основываясь на ответе ghostdog74)

for dir in directory/*                                                     
do                                                                                 
  echo ${dir}                                                                  
done

чтобы сжать целую кучу файлов по каталогу

for dir in directory/*
do
  zip -r ${dir##*/} ${dir}
done                                               
2 голосов
/ 21 января 2010

find . -type d -maxdepth 1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...