Как составить список подкаталогов каталога?

Предполагая, что ваш main_script.shдовольно стандартный и проходит 0для успешного запуска и 1для неудачного запуска, вы можете проверить статус через $?следующим образом:

./main_script.sh
if [ $? -eq 0 ]; then
   ./report_success.sh
else
   ./report_failure.sh
fi
0
27.09.2021, 00:41
3 ответа

Предполагая, что вы используете инструменты GNU, вы можете использовать GNU basenameдля получения имен всех подкаталогов в конкретном каталоге. Затем вы можете использовать paste, чтобы отформатировать это как список, разделенный пробелом -.

basename -a /some/path/*/ | paste -d ' ' -s -

Приведенная выше команда использует тот факт, что GNU basenameимеет параметр -aдля возврата части имени файла из нескольких путей, заданных в качестве операндов в его командной строке.

Мы используем шаблон файла -подстановки, оканчивающийся на /, чтобы сгенерировать пути для GNU basename. Только каталоги могут соответствовать такому шаблону.

В конце концов, pasteсоздает список, разделенный пробелами -, из списка, разделенного новой строкой -, созданного GNU basename.

Обратите внимание, что было бы трудно проанализировать сгенерированный список имен файлов, если какое-либо из исходных имен каталогов содержит символы пробела.

Обратите внимание: если каталог содержит символические ссылки, этот метод попытается перейти по этим символическим ссылкам.


Ограничив нас от использования каких-либо внешних инструментов, мы могли бы использовать массив в оболочке bashдля хранения путей к каталогам и управления ими.

shopt -s nullglob

topdir=/some/path

dirpaths=( "$topdir"/*/ )
dirpaths=( "${dirpaths[@]#$topdir/}" )
dirpaths=( "${dirpaths[@]%/}" )

printf '%s\n' "${dirpaths[*]}"

Приведенный выше код оболочки расширяет тот же шаблон подстановки, который мы использовали в первой части этого ответа, но сохраняет полученные пути к каталогам в массиве dirpaths. Затем он удаляет известный префикс $topdir/из каждого элемента массива и конечный /перед печатью массива в виде одной строки имен, разделенных пробелом -. Разделителем, используемым между именами в последней строке, будет первый символ из $IFS, который по умолчанию является пробелом.


Используя find, вы можете искать подкаталоги в конкретном верхнем каталоге, который вас интересует, не возвращая при этом сам верхний каталог. Вы также должны остановить findот перехода в подкаталоги.

topdir=/some/path
find "${topdir%/}/." ! -name. -prune -type d -exec basename {} \; | paste -d ' ' -s -

Приведенная выше команда избегает начальной точки поиска, используя отрицательный тест -name.и он обрезает дерево поиска с помощью -prune, так что findне рекурсивно спускается в какие-либо подкаталоги. Мы вызываем basenameдля каждого найденного каталога, который выводит имена файлов каталогов на отдельные строки. В качестве последнего шага мы передаем результат от findдо pasteдля форматирования вывода в список, разделенный пробелом -в одной строке.

В GNU findэто можно записать как

find /some/path -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | paste -d ' ' -s -

Использование findподобным образом приведет к отображению каталогов со скрытыми именами, и вы не увидите никаких каталогов, связанных символически.


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

print -r -- /some/path/*(/:t)

В этой команде используется квалификатор glob, /:t, состоящий из двух частей, влияющий на предыдущий шаблон подстановки /some/path/*. /заставляет шаблон соответствовать только каталогам (, не связанным символически; для этого используйте -/), а :tизвлекает «хвост» каждого сгенерированного имени пути, то есть компонент имени файла.

Команда print -rпечатает свои аргументы с пробелами в качестве разделителей, избегая расширения управляющих последовательностей, таких как \nили \t, в данных. Использование --для отделения операндов от опций (также работает с -, как в оболочке ksh), гарантирует, что имена каталогов, полученные в результате расширения glob, не будут приниматься в качестве опций, даже если они начинаются с -.

Вы можете использовать это в оболочке bashдля создания списка.

zsh -c 'print -r -- /some/path/*(/:t)'
3
27.09.2021, 06:00

Поскольку вы уже знаете каталог, из которого вы перечисляете подкаталоги, вы можете использовать следующее...

find /home/x/y -maxdepth 1 -type d -printf '%P '
0
27.09.2021, 18:54

Вот мое предложение с использованием цикла for:

$ echo "$(for node in $(ls ~/); do if test -d "${node}"; then printf "${node} "; fi; done)"
Desktop Documents Downloads Music Pictures Public Templates Videos

Альтернативное использованиеfind:

$ echo "$(for node in $(find ~/ -mindepth 1 -maxdepth 1 -type d); do printf "$(basename ${node}) "; done)"
.mozilla Videos Pictures Music Documents Public Templates Downloads.gnupg.config.local.cache Desktop

Редактировать:Что касается их комментария , вам нужно будет изменить переменную IFSдля каталогов с пробелами:

$ IFS_orig=${IFS}
$ IFS=$'\n'
$ echo "$(for node in $(ls ~/); do if test -d "${node}"; then printf "'${node}' "; fi; done)"
'Desktop' 'Documents' 'Downloads' 'Music' 'My Test' 'Pictures' 'Public' 'Templates' 'Videos'

$ IFS=${IFS_orig}

Редактировать:Самый простой вариант — использоватьls -d *:

$ ls -d *
 Desktop   Documents   Downloads   Music  'My Test'   Pictures   Public   Templates   Videos

Также забыл, что в циклах forследует testиспользовать абсолютный или относительный путь:

$ echo "$(for node in $(ls "${HOME}"); do if test -d "${HOME}/${node}"; then printf "'${node}' "; fi; done)"
'Desktop' 'Documents' 'Downloads' 'Music' 'My Test' 'Pictures' 'Public' 'Templates' 'Videos'
-1
27.09.2021, 21:36

Теги

Похожие вопросы