Wie verwende ich "find", um zum Verzeichnis dieser Datei zu gelangen?

11

Ich möchte eine Datei finden und dann das Verzeichnis eingeben, das sie enthält. Ich habe es find /media/storage -name "Fedora" | xargs cdaber natürlich versucht den is not a directoryFehler.

Wie gebe ich das übergeordnete Verzeichnis mit einem einzeiligen Befehl ein?

Hrvoje T.
quelle
1
Und was ist, wenn mehrere Dateien von mehreren Speicherorten vorhanden sind?
Sergiy Kolodyazhnyy
@Serg Ich suche nach Fedora * .iso-Datei und ich weiß, dass es nur eine gibt. Wenn es mehr als eine gäbe, würde sie in die erste Direcotry eintreten, denke ich
Hrvoje T
In Bash mit shopt -s globstarkönnten Sie cd /media/storage/**/Fedora, aber das hört nicht auf, den Glob beim ersten Match auszuwerten (es ist also langsamer als die Lösung von steeldriver. Für die interaktive Verwendung würde ich normalerweise nach der Maus greifen und den Verzeichnisnamen kopieren / einfügen). (und Alt + Rücktaste nach Bedarf, um nachlaufende Pfadkomponenten zu entfernen, die ich nicht wollte), aber wenn Sie dies häufig tun, könnte es sich lohnen, eine Shell-Funktion zu erstellen.
Peter Cordes
1
Übrigens xargs cdkann ich unmöglich arbeiten. cdkann nur als integrierte Shell arbeiten, da der Kontext der Shell selbst geändert werden muss. Ein xargsuntergeordneter Prozess kann das auf keinen Fall . IDK, wenn Sie das mit "natürlich" gemeint haben oder wenn der Pfad, der findgedruckt wird, Leerzeichen enthält, die durch xargs geteilt werden, da Sie nichts verwendet haben -d \noder so. Oder find -exec {} \;.
Peter Cordes
Hinweis: Sie können nicht so laufen cd. cdist ein eingebauter Bash, wenn cdein separater Befehl wäre, würde er (sein eigenes) Verzeichnis ändern und dann beenden (Sie werden zur Shell zurückkehren, die sich im selben Zustand wie zuvor befindet, keine Änderung des Verzeichnisses).
Strg-Alt-Delor

Antworten:

14

Zumindest wenn Sie GNU haben find, können -printf '%h'Sie das Verzeichnis abrufen

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Also könntest du es wahrscheinlich tun

cd "$(find /media/storage -name "Fedora" -printf '%h' -quit)"

Das -quitsollte verhindern, dass mehrere Argumente für cdden Fall, dass mehr als eine Datei übereinstimmt.

Steeldriver
quelle
1
-quitwird auch nicht unbedingt unterstützt. In NetBSD heißt es -exit, siehe unix.stackexchange.com/a/62883/117599
phk
2
Wenn es kein printf gibt, könnten Sie stattdessen -exec dirname ausführen?
Guy
@ Guy gute Idee ja, das klingt wie es auch funktionieren sollte
Steeldriver
6

Ähnlich wie bei der Steeldriver- Lösung, jedoch mit -execdir(wenn Sie dies findunterstützen, wie GNUs oder FreeBSDs find) in Kombination mit pwd:

cd "$(find /media/storage -name "Fedora" -execdir pwd \; -quit)"

-quitist optional, wenn nur ein einziges Ergebnis vorliegt und das Crawlen des gesamten Verzeichnisses kein Problem darstellt. Auf NetBSD ist es -exitund auf OpenBSD existiert es nicht.

phk
quelle
Und wofür ist \;?
Hrvoje T
1
@HrvojeT Genau wie hier -execwird finddas Ende der Parameter angegeben, die der Befehl ausführen soll. Da wir pwdhier aber ohne Parameter aufrufen wollen , setzen wir das \;Recht danach.
Phk
Gibt es findImplementierungen, die execdir unterstützen, aber nicht -printf %h? Scheint mir unwahrscheinlich. Leider wird keiner von POSIX benötigt: /
Peter Cordes
1
@ PeterCordes FreeBSDs find: freebsd.org/cgi/man.cgi?find%281%29 ( Ich habe es gerade bei einer FreeBSD 11-Installation bestätigt.)
phk
@PeterCordes Gleiches gilt für NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) und OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ). Letzteres unterstützt -quit/ -exitüberhaupt nicht.
Phk
5

Sie können find dazu bringen, eine neue Shell in dem gefundenen Verzeichnis auszuführen.

exec find /media/storage -name "Fedora" -execdir "$SHELL" \;

Danach ist das aktuelle Verzeichnis dasjenige, in dem sich eine Datei mit dem Namen Fedora befindet. ;)

Offensichtlich funktioniert dies nur dann, wenn Sie Befehle interaktiv eingeben.

BenGoldberg
quelle
4

Mit zsh:

cd /media/storage/**/Fedora([1]:h)

bis cdin das ersten (in alphabetischer Reihenfolge) Verzeichnis , das eine Datei mit dem Namen enthält Fedora.

  • **: jede Ebene von Verzeichnissen (versteckte Verzeichnisse werden standardmäßig weggelassen, verwenden Sie das DGlob-Qualifikationsmerkmal, um sie einzuschließen )
  • [1]: nur der erste
  • :h: head modifier: nimm den dirnamen.

Im Gegensatz dazu cd "$(find ...)"funktioniert es auch, wenn der Verzeichnisname mit einem Zeilenumbruch endet. Ein weiterer Vorteil ist , dass Sie einen bekommen würden keine Übereinstimmung Fehlermeldung , wenn kein passendes Verzeichnis ist (während in den meisten Schalen cd ""würde nichts still tun).

Ein Nachteil ist, dass es das ganze kriechen würde, /media/storagebevor es zurückkehrt.

Stéphane Chazelas
quelle
In Bash wird cdbei mehreren Argumenten ohnehin nur das erste Argument angezeigt. Dies cd $(dirname /media/storage/**/Fedora)würde (mit shopt -s globstar) funktionieren, wenn der Pfad keine Leerzeichen enthält. Um es richtig zu zitieren, denke ich, dass ein Bash-Array am einfachsten ist : target=(/media/storage/**/Fedora); cd "${target%/*}". Zu diesem Zeitpunkt wäre es jedoch schneller gewesen, die Suchausgabe mit der Maus zu kopieren / einzufügen, anstatt sie interaktiv zu erstellen.
Peter Cordes
2
@PeterCordes, viele dirnameImplementierungen akzeptieren nicht mehr als ein Argument. Beachten Sie, dass es sich nicht um Leerzeichen handelt , sondern um Zeichen, die sich derzeit in $IFS(Leerzeichen, Tabulatoren und Zeilenumbrüche) und Platzhalterzeichen befinden. Beachten Sie, dass , ob bash‚s cdakzeptieren mehr als ein Argument hängt davon ab , wie es kompiliert wurde ( CD_COMPLAINSin config-top.h). Man kann sich vorstellen, dass zukünftige Versionen von bashschließlich auch die Zwei-Argumente-Funktion wie in zsh implementieren werden.
Stéphane Chazelas
Vielen Dank. Ich habe mir gerade die Manname-Manpage zu GNU coreutils angesehen. Die Dirname-Version ist sowieso schrecklich; Ich habe es nur als etwas erwähnt, das Sie interaktiv ausprobieren könnten, falls es funktionieren sollte. Meine Array-basierte Version leidet unter keinem dieser Probleme, da "${target%*/}"sie nur auf das erste Array-Element (mit dem entfernten /Fedora) erweitert wird. Ich denke, dass die Version gegenüber allen möglichen Zeichen im Pfadnamen völlig robust ist.
Peter Cordes