Знайдіть список каталогів на одному рівні глибоко від відповідного каталогу


13

Я намагаюся отримати список каталогів, які містяться в певній папці.

З огляду на ці приклади папок:

foo/bar/test
foo/bar/test/css
foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI

Я хотів би отримати команду, яка поверне:

XYZ
ABC
DEF
GHI

По суті, я шукаю папки, які знаходяться всередині wp-content / plugins /

Використання findзнайшло мене найближчим, але я не можу його використовувати -maxdepth, оскільки папка міняється далеко від того, де я шукаю.

Виконання наведених нижче повертає всі дочірні каталоги, рекурсивно.

find -type d -path *wp-content/plugins/*

foo/bar/wp-content/plugins/XYZ
foo/bar/wp-content/plugins/XYZ/js
foo/bar/wp-content/plugins/XYZ/css
baz/wp-content/plugins/ABC
baz/wp-content/plugins/ABC/inc
baz/wp-content/plugins/ABC/inc/lib
baz/wp-content/plugins/DEF
bat/bar/foo/blog/wp-content/plugins/GHI

Відповіді:


14

Просто додайте -pruneтак, щоб знайдені каталоги не спускалися в:

find . -type d -path '*/wp-content/plugins/*' -prune -print

Вам потрібно цитувати це, *wp-content/plugins/*оскільки це також глобус оболонки.

Якщо ви хочете тільки імена каталогів , на відміну від їх повного шляху, з GNU find, ви можете замінити -printз -printf '%f\n'або припускаючи , що шляхи до файлів не містять символи нового рядка, конвеєру висновок вище команди на awk -F / '{print $NF}'або sed 's|.*/||'(також за умови , що шляхи до файлів містять лише дійсні символи).

З zsh:

printf '%s\n' **/wp-content/plugins/*(D/:t)

**/є будь-яким рівнем підкаталогів (функція Виникнувши в zshна початку нічних сорочок, і тепер в більшості інших оболонок подобається ksh93, tcsh, fish, bash, yashхоча в цілому в рамках якого - то варіанти), (/)щоб вибрати тільки файли типу каталогу , Dвключити приховані (точку) з них, :tв отримати хвіст (ім'я файлу).


Ця знахідка перетворить нові рядки в dirs на а ?. Для bash, (як зазначено в запитанні) це працює .
Ісаак

@sorontar, findреалізації, які видають ?або будь-який символ заміни, або будь-яку форму пропуску для недрукуваних символів, роблять це лише тоді, коли вихід надходить до терміналу, а не тоді, коли він переходить до труби, як тут.
Стефан Шазелас

У першій (і єдиній, не zsh) команді, що є у вашій відповіді, немає труб, це те, що я перевірив, і це те, що змінює нові рядки. Як говорилося у вашому трубопроводі: "припускаючи, що шляхи файлів не містять символів нового рядка", ви вже визнали, що він також не відповідає новим рядкам.
Ісаак

@sorontar, вибачте, я думав, що ви коментуєте другу частину, щоб сказати, що це буде добре, оскільки нові рядки будуть уникнути, щоб не порушити припущення, про яке ми робимо sed/ awkщо всі файли знаходяться в рядку. Тепер можна стверджувати, що отримання ABC?BCDабо ABC\nBCDдля інтерактивного / термінального виходу було б корисніше, ніж отримання двох ABCта BCDрядків для виклику dir $'ABC\nBCD. Це на рівні презентації користувача, ми також можемо зазначити, що для файлу, який називається $'AB\bC', коли вихід надходить до терміналу, ви AC?
бачитесь

Знайти за допомогою -prune і використання printf для зміни формату виводу дало мені саме те, про що я просив. Ідеально - дякую!
Нік

4

Bash-ical:

shopt -s globstar
printf "%s\n" **/wp-content/plugins/*

відбитки:

bat/bar/foo/blog/wp-content/plugins/GHI
baz/wp-content/plugins/ABC
baz/wp-content/plugins/DEF
foo/bar/wp-content/plugins/XYZ

або

shopt -s globstar
for d in **/wp-content/plugins/*; do printf "%s\n" ${d##*/}; done

відбитки:

GHI
ABC
DEF
XYZ

Ні, це також буде друкувати файли всередині ріжків. Прочитайте, будь ласка, мою відповідь.
Ісаак

Влучне зауваження; Дякую! Я відтворив їх структуру каталогів, але не розміщував у них тестових файлів.
Джефф Шаллер

4

Ви могли findповторити, наприклад:

find / -type d -path *wp-content/plugins -exec find {} -maxdepth 1 -mindepth 1 -type d \;

3

Для Bash: просто (працює для файлів / dirs з пробілами та новими рядками ):

shopt -s globstar                    # allow ** for several dirs.
a=(**/wp-content/plugins/*/)         # capture only wanted dirs.
a=("${a[@]%/}")                      # remove trailing slash (dirs) `/`.
printf '%s\n' "${a[@]##*/}"          # print only the last dir name.

Друк:

GHI
ABC
DEF
XYZ

Навіть якщо створені файли.


Зауважте, що він не заглядає всередині прихованих файлів, пропускає приховані файли (див. dotglobОпцію, якщо це небажано) і включає в себе додаткові посилання на каталоги на додаток до каталогів ( **також переходитиме посилання в bash 4.2 і раніше).
Стефан Шазелас

@ StéphaneChazelas приховані файли? Питання задає ніхто, тільки панове. Так, приховані бруси можна було вибрати самостійно (як особливість, за бажанням). І так, символьні посилання не є поперечними в поточній версії bash.
Ісаак

1
будь ласка, не сприймайте мої коментарі як агресію. Я схвалив вашу відповідь і додав під собою записку, щоб вказати на деякі факти, які не обов'язково очевидні. findне виключає жодного файлу. глобуси виключають крапкові файли, варто вказати на різницю між ними.
Стефан Шазелас

3

treeКоманда призначена саме для цієї мети. Глибину можна контролювати за допомогою -Lпрапора. Ось приклад на локальному сайті Wordpress, який я підтримую:

$ tree -L 1 wp-content/
wp-content/
├── index.php
├── plugins
└── themes

2 directories, 1 file

$ tree -L 2 wp-content/
wp-content/
├── index.php
├── plugins
   ├── akismet
   ├── contact-form-7
   ├── index.php
   └── wordpress-seo
└── themes
    ├── index.php
    ├── twentyfifteen
    └── twentysixteen

11 directories, 3 files

$ tree -L 1 wp-content/plugins/
wp-content/plugins/
├── akismet
├── contact-form-7
├── index.php
└── wordpress-seo

5 directories, 1 file

1

Спираючись на відповідь DopeGhoti, як щодо петлі відповідності:

find / -type d -iregex '.*/wp-content/plugins' -print0 | while read -r -d $'\0' D; do
    find "$D" -maxdepth 2 -mindepth 1
done

Причина цього робити в тому, що ви можете вважати його заплутаним / громіздким з кількома -exec's, в той час як все-таки уникати проблем із своєрідними іменами файлів, що містять \ n' 'і т.д.


0

Спираючись на те, що ви почали:

find -type d -path *wp-content/plugins/* | egrep -o "wp-content/plugins/[^/]+($|/)" | sed -r "s~wp-content/plugins/([^/]+)($|/)~\1~" | uniq  

egrep схоплює * wp-content / plugins / * та будь-які символи до наступної косої риски / або в кінці рядка $ - що включає бажану частину.

sed , за допомогою роздільника ~, вибирає потрібну частину, використовуючи перший набір дужок (), і використовує \ 1 (що ви хочете) як заміну всього

uniq фільтрує повторювані результати

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.