Как перебрать каталоги в Linux?

Вопрос:

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

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

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

Лучший ответ:
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

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

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

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

  • -type d выглядит только для каталогов

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

E voila!

Ответ №1

Все ответы до сих пор используют 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

Ответ №2

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

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

Ответ №3

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

Вдохновленный 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)

Исходный пост (не работает с пробелами)

Вдохновленный Boldewyn: пример цикла с командой find.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
echo $D ;
done

Ответ №4
find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"

Ответ №5

Чаще всего я использую технику 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.

Ответ №6

find . -type d -maxdepth 1

Ответ №7

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

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

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

for dir in directory/*
do
zip -r ${dir##*/} ${dir}
done

Ответ №8

Если вы хотите выполнить несколько команд в цикле for, вы можете сохранить результат find с mapfile (bash> = 4) в качестве переменной и просмотреть массив с помощью ${dirlist[@]}. Он также работает с каталогами, содержащими пробелы.

Команда find основана на ответе Болдевина. Дополнительную информацию о команде find можно найти там.

IFS=""
mapfile -t dirlist < <( find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n' )
for dir in ${dirlist[@]}; do
echo ">${dir}<"
# more commands can go here ...
done

Оцените статью
TechArks.Ru
Добавить комментарий