Suchen Sie eine Liste der Verzeichnisse, die eine Ebene tief im übereinstimmenden Verzeichnis liegen

13

Ich versuche, eine Liste der Verzeichnisse abzurufen, die in einem bestimmten Ordner enthalten sind.

Angesichts dieser Beispielordner:

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

Ich möchte einen Befehl, der zurückgibt:

XYZ
ABC
DEF
GHI

Im Wesentlichen suche ich nach Ordnern, die sich in wp-content / plugins / befinden

Die Verwendung findhat mich am nächsten gebracht, aber ich kann sie nicht verwenden -maxdepth, da der Ordner variabel von dem Ort entfernt ist, an dem ich suche.

Wenn Sie Folgendes ausführen, werden alle untergeordneten Verzeichnisse rekursiv zurückgegeben.

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
Nick
quelle

Antworten:

14

Fügen Sie einfach ein hinzu, -prunedamit die gefundenen Verzeichnisse nicht in folgende Kategorien absteigen:

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

Sie müssen das zitieren, *wp-content/plugins/*da es auch ein Shell Glob ist.

Wenn Sie mit GNU nur die Verzeichnisnamen im Gegensatz zu ihrem vollständigen Pfad möchten find, können Sie die -printmit -printf '%f\n'oder unter der Annahme ersetzen, dass die Dateipfade keine Zeilenumbruchzeichen enthalten, die Ausgabe des obigen Befehls an awk -F / '{print $NF}'oder weiterleiten sed 's|.*/||'(auch unter der Annahme, dass die Dateipfade enthalten nur gültige Zeichen).

Mit zsh:

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

**/ist ein beliebige Verzeichnisse einer Ebene ( mit Ursprung Funktion in zshin den frühen nighties, und jetzt in den meisten anderen Shells wie gefunden ksh93, tcsh, fish, bash, yashobwohl in der Regel unter einer Option), (/)wählt nur Dateien vom Typ Verzeichnis , Denthält versteckt (dot) diejenigen, :tzu Holen Sie sich den Schwanz (Dateiname).

Stéphane Chazelas
quelle
Dieser Fund konvertiert Zeilenumbrüche in Verzeichnissen in a ?. Für Bash (wie in der Frage markiert) funktioniert dies .
Sorontar
@sorontar, findImplementierungen, die ein ?oder ein Ersatzzeichen oder eine Form der Escape-Funktion für nicht druckbare Zeichen ausgeben, tun dies nur, wenn die Ausgabe an ein Terminal geht, nicht, wenn sie an eine Pipe wie hier geht.
Stéphane Chazelas
Der erste (und einzige nicht zsh) Befehl, der in Ihrer Antwort enthalten ist, enthält keine Pipes. Er ist der von mir getestete und ändert die Zeilenumbrüche. Wie bereits erwähnt: "Angenommen, die Dateipfade enthalten keine Zeilenumbruchzeichen", haben Sie bereits zugegeben, dass dies auch bei Zeilenumbrüchen fehlschlägt.
Sorontar
@sorontar, tut mir leid, ich dachte, Sie kommentieren den zweiten Teil, um zu sagen, dass es in Ordnung wäre, da die Zeilenumbrüche maskiert würden, damit die Annahme, die wir für sed/ awkalle Dateien in einer Zeile haben, nicht gebrochen wird. Nun kann man argumentieren, dass es nützlicher wäre , eine ABC?BCDoder ABC\nBCDfür eine interaktive / Terminal-Ausgabe zu erhalten, als zwei ABCund BCDZeilen für ein aufgerufenes Verzeichnis zu erhalten $'ABC\nBCD. Das ist auf der Ebene der Benutzerpräsentation, wir könnten auch darauf hinweisen, dass für eine Datei namens $'AB\bC', wenn die Ausgabe an ein Terminal geht, Sie ACohne einen solchen ?Ersatz sehen würden ...
Stéphane Chazelas
Suchen mit -prune und Verwenden von printf zum Ändern des Ausgabeformats gab mir genau das, wonach ich gefragt hatte. Perfekt danke!
Nick
4

Bash-ically:

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

Drucke:

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

oder

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

Drucke:

GHI
ABC
DEF
XYZ
Jeff Schaller
quelle
Nein, das druckt auch Dateien innerhalb der Verzeichnisse. Bitte lesen Sie meine Antwort.
Sorontar
Guter Punkt; Danke! Ich hatte ihre Verzeichnisstruktur neu erstellt, aber keine Testdateien darin abgelegt.
Jeff Schaller
4

Sie könnten einen findRückgriff haben, eine Art:

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

Für Bash: Einfach (funktioniert für Dateien / Verzeichnisse mit Leerzeichen und Zeilenumbrüchen ):

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.

Wll drucken:

GHI
ABC
DEF
XYZ

Auch wenn Dateien erstellt wurden.

Sorontar
quelle
Beachten Sie, dass es nicht in versteckte Verzeichnisse schaut, versteckte Dateien überspringt (siehe die dotglobOption, wenn dies unerwünscht ist) und zusätzlich zu Verzeichnissen Symlinks zu Verzeichnissen enthält ( **würde auch Symlinks in Bash 4.2 und früher durchlaufen).
Stéphane Chazelas
@ StéphaneChazelas versteckte Dateien? Die Frage verlangt keine, nur dirs. Ja, versteckte Verzeichnisse können unabhängig voneinander ausgewählt werden (auf Wunsch als Funktion). Und ja, Symlinks sind in der aktuellen Version von bash nicht quer.
Sorontar
1
Bitte betrachte meine Kommentare nicht als Aggressionen. Ich habe Ihre Antwort positiv bewertet und eine Notiz darunter hinzugefügt, um auf einige Fakten hinzuweisen, die nicht unbedingt offensichtlich sind. findschließt keine Datei aus. globs schließt Punktdateien aus, es lohnt sich, auf einen Unterschied zwischen den beiden hinzuweisen.
Stéphane Chazelas
3

Der treeBefehl ist genau für diesen Zweck ausgelegt. Die Tiefe kann mit der -LFlagge gesteuert werden . Hier ist ein Beispiel auf einer lokalen Wordpress-Site, die ich pflege:

$ 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
dotancohen
quelle
1

Aufbauend auf der Antwort von DopeGhoti, wie wäre es mit einer Matching-Schleife:

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

Der Grund dafür ist, dass Sie es möglicherweise mit mehreren verwirrend / umständlich finden -exec, während Sie dennoch Probleme mit bestimmten Dateinamen vermeiden, die \ n '' usw. enthalten. -Print0 verwendet Nulltrennzeichen zwischen den Ergebnissen.

Ed Neville
quelle
0

Aufbauend auf dem, was Sie begonnen haben:

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

egrep greift nach * wp-content / plugins / * und allen Zeichen bis zum nächsten Schrägstrich / oder Zeilenende $ - einschließlich des gewünschten Teils.

sed wählt mit einem Trennzeichen ~ den gewünschten Teil mit dem ersten Satz von Klammern () aus und verwendet \ 1 (was Sie wollen) als Ersatz für alles

uniq filtert doppelte Ergebnisse heraus

MikeD
quelle