Ich möchte rekursiv nach jeder *.pdf
Datei in einem Verzeichnis suchen, ~/foo
dessen Basisname mit dem Namen des übergeordneten Verzeichnisses der Datei übereinstimmt.
Angenommen, die Verzeichnisstruktur ~/foo
sieht folgendermaßen aus
foo
├── dir1
│ ├── dir1.pdf
│ └── dir1.txt
├── dir2
│ ├── dir2.tex
│ └── spam
│ └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf
Das Ausführen meines gewünschten Befehls würde zurückkehren
~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
Ist dies mit find
oder einem anderen Kerndienstprogramm möglich? Ich gehe davon aus, dass dies mit der -regex
Option möglich ist, find
bin mir aber nicht sicher, wie ich das richtige Muster schreiben soll.
Antworten:
Mit GNU
find
:-regextype egrep
Verwenden Sie egrep style regex..*/
Match Großeltern Direktiven.([^/]+)/
Übereinstimmung mit dem übergeordneten Verzeichnis in einer Gruppe.\1\.pdf
Verwenden Siebackreference
diese Option, um den Dateinamen als übergeordnetes Verzeichnis abzugleichen.aktualisieren
Einer (ich für meinen Teil) könnte denken, dass
.*
das gierig genug ist, es ist unnötig,/
vom Eltern-Matching auszuschließen :Der obige Befehl funktioniert nicht gut, weil er rechnet
./a/b/a/b.pdf
:.*/
Streichhölzer./
(.+)/
Streichhölzera/b/
\1.pdf
Streichhölzera/b.pdf
quelle
find . -regex '.*/\([^/]*\)/\1\.pdf'
und dann würde es sogar mit BSD funktionierenfind
.Die traditionelle Schleifenvariante der
find .. -exec sh -c ''
Verwendung der Shell-Konstrukte zur Übereinstimmung mit dem Basisnamen und dem unmittelbaren Pfad darüber wäre unten.Aufschlüsselung der einzelnen Parametererweiterungen
file
enthält den vollständigen Pfad der.pdf
vomfind
Befehl zurückgegebenen Datei"${file##*/}"
enthält nur den Teil nach dem letzten,/
dh nur den Basisnamen der Datei"${file%/*}"
enthält den Pfad bis zum Ende,/
dh mit Ausnahme des Basisnamens des Ergebnisses"${path##*/}"
enthält den Teil nach dem letzten/
aus derpath
Variablen, dh den unmittelbaren Ordnerpfad über dem Basisnamen der Datei"${base%.*}"
enthält den Teil des Basisnamens, bei dem die.pdf
Erweiterung entfernt wurdeWenn also der Basisname ohne Erweiterung mit dem Namen des unmittelbaren Ordners oben übereinstimmt, drucken wir den Pfad.
quelle
Die Umkehrung von Inians Antwort , dh nach Verzeichnissen suchen und dann prüfen, ob sie eine Datei mit einem bestimmten Namen enthalten.
Im Folgenden werden die Pfadnamen der gefundenen Dateien relativ zum Verzeichnis gedruckt
foo
:${dirpath##*/}
wird durch den Dateinamen des Verzeichnispfads ersetzt und kann durch ersetzt werden$(basename "$dirpath")
.Für Leute, die die Kurzschlusssyntax mögen:
Der Vorteil dieser Vorgehensweise besteht darin, dass Sie möglicherweise mehr PDF-Dateien als Verzeichnisse haben. Die Anzahl der beteiligten Tests wird reduziert, wenn man die Abfrage um die kleinere Anzahl (die Anzahl der Verzeichnisse) einschränkt.
Wenn ein einzelnes Verzeichnis beispielsweise 100 PDF-Dateien enthält, wird nur versucht, eine davon zu erkennen, anstatt die Namen aller 100 Dateien mit denen des Verzeichnisses zu vergleichen.
quelle
mit
zsh
:Beachten Sie, dass
**/
Symlinks zwar nicht folgen, aber folgen*/
.quelle
Es wurde nicht angegeben, aber hier ist eine Lösung ohne reguläre Ausdrücke, wenn jemand interessiert ist.
Wir können
find . -type f
nur Dateien abrufen, dann die Bedingung verwendendirname
undbasename
schreiben. Die Dienstprogramme haben das folgende Verhalten:basename
Gibt nur den Dateinamen nach dem letzten zurück/
:dirname
gibt den gesamten Weg bis zum Finale/
:Gibt daher
basename $(dirname $file)
das übergeordnete Verzeichnis der Datei an.Lösung
Kombinieren Sie das Obige, um die Bedingung zu bilden
"$(basename $file)" = "$(basename $(dirname $file))".pdf
, und drucken Sie dann jedes Ergebnis nur aus,find
wenn diese Bedingung true zurückgibt.Im obigen Beispiel haben wir ein Verzeichnis / eine Datei mit Leerzeichen im Namen hinzugefügt, um diesen Fall zu behandeln (danke an @Kusalananda in den Kommentaren).
quelle
Final Thesis.pdf
(mit einem Leerzeichen) unterbrochen .Ich mache jeden Tag Bash Globbing, einfache Loop-Over-String-Tests über das Find- Programm. Nennen Sie mich irrational, und obwohl es vielleicht suboptimal ist, macht solch einfacher Code den Trick für mich: lesbar und wiederverwendbar, sogar befriedigend!. Lassen Sie mich daher eine Kombination vorschlagen aus:
• bash globstar :
for f in ** ; do ...
** Durchläuft alle Dateien im aktuellen Verzeichnis und alle Unterordner, um den Globstar-Status in Ihrer aktuellen Sitzung zu überprüfen :shopt -p globstar
. So aktivieren Sie globstar :shopt -s globstar
.• "file" utlity :
if [[ $(file "$f") =~ pdf ]]; then ...
Zum Überprüfen des tatsächlichen Dateiformats auf PDF - robuster als nur das Testen der Dateierweiterung• Basisname, Verzeichnisname : Zum Vergleichen des Dateinamens mit dem Namen des Verzeichnisses unmittelbar darüber.
basename
gibt den Dateinamen zurück -dirname
gibt den gesamten Verzeichnispfad zurück - kombinieren Sie die beiden Funktionen, um nur das eine Verzeichnis zurückzugeben, das die übereinstimmende Datei enthält. Ich habe jedes in eine Variable ( _mydir und _myf ) eingefügt, um dann einen einfachen Test mit = ~ für den String-Abgleich durchzuführen .Eine Subtilität: Entfernen Sie alle "Punkte" im Dateinamen, um zu vermeiden, dass der Dateiname mit dem aktuellen Verzeichnis übereinstimmt, dessen Verknüpfung ebenfalls "ist". - Ich habe die direkte Zeichenfolgenersetzung für die Variable _myf verwendet :
${_myf//./}
- nicht sehr elegant, aber es funktioniert. Positive Übereinstimmungen geben den Pfad jeder Datei zurück - zusammen mit dem vollständigen Pfad des aktuellen Ordners, indem der Ausgabe Folgendes vorangestellt wird :$(pwd)/
.Code
quelle