Я пишу 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!
Все ответы до сих пор используют 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
Вы можете прокручивать все каталоги, включая скрытые 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
Работает с каталогами, содержащими пробелы
Вдохновленный 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
find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"
Чаще всего я использую технику 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
.
find . -type d -maxdepth 1
минимальный цикл bash, из которого вы можете построить (основанный на ответе ghostdog74)
for dir in directory/*
do
echo ${dir}
done
сжать целую кучу файлов по каталогу
for dir in directory/*
do
zip -r ${dir##*/} ${dir}
done
Если вы хотите выполнить несколько команд в цикле 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