Come posso usare `find` per andare alla directory di quel file


11

Voglio trovare un file e quindi inserire la directory che lo contiene. Ho provato find /media/storage -name "Fedora" | xargs cdma, ovviamente, ho l' is not a directoryerrore.

Come posso inserire la sua directory principale con un comando a una riga?


1
E se ci fossero più file da più posizioni?
— Sergiy Kolodyazhnyy,

@Serg Sto cercando il file Fedora * .iso e so che ce n'è solo uno. Se ce ne fossero più di uno entrerebbe nella prima regia, credo
— Hrvoje T

In base shopt -s globstar, potresti cd /media/storage/**/Fedora, ma ciò non smette di valutare il glob alla prima corrispondenza (quindi è più lento della soluzione di Steeldriver. Per un uso interattivo, ciò che normalmente farei è raggiungere il mouse e copiare / incollare il nome della directory, (e alt + backspace se necessario per eliminare i componenti del percorso finale che non volevo), ma se lo fai molto immagino che valga la pena fare una funzione shell.
— Peter Cordes,

1
A proposito, xargs cdnon è possibile che funzioni. cdpuò funzionare solo come shell incorporata, perché deve modificare il contesto della shell stessa. Non è possibile che un xargsprocesso figlio possa farlo. IDK se questo è ciò che intendevi per "ovviamente", o se il percorso che findstampa contiene spazi, che sono divisi da xargs poiché non hai usato -d \no altro. Or find -exec {} \;.
— Peter Cordes,

nota: non puoi correre cdcosì. cdè un bash incorporato, se cdfosse un comando separato, allora cambierebbe (il suo) dir, e poi uscirà (ritornando alla shell, che è nello stesso stato di prima, nessun cambio di dir).
— ctrl-alt-delor,

Risposte:


14

Almeno se hai GNU find, puoi usare -printf '%h'per ottenere la directory

       %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
              ".".

Quindi probabilmente potresti farlo

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

L' -quitdovrebbe evitare che più argomenti cdnel caso più di un file corrisponde.


1
-quitinoltre non è necessariamente supportato. In NetBSD si chiama -exit, vedi unix.stackexchange.com/a/62883/117599
— phk

2
Se non c'è printf, potresti invece fare -exec dirname?
— Guy

@Guy buona idea sì, sembra che dovrebbe funzionare anche lui
— steeldriver

6

Simile alla soluzione di Steeldriver ma usando -execdir(se il tuo lo findsupporta, come GNU o FreeBSD find) in combinazione con pwd:

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

-quitè facoltativo nel caso in cui vi sia un solo risultato e la scansione dell'intera directory non presenta alcun problema. Su NetBSD è -exite su OpenBSD non esiste.


E a cosa serve \;?
— Hrvoje T,

1
@HrvojeT Proprio come -execracconta findla fine dei parametri per l'esecuzione del comando. Ma dal momento che vogliamo chiamare pwdsenza parametri qui, ci mettiamo \;subito dopo.
— phk,

Ci sono findimplementazioni che supportano execdir ma non -printf %h? Mi sembra improbabile. Sfortunatamente nessuno dei due è richiesto da POSIX: /
— Peter Cordes il

1
@PeterCordes di FreeBSD find: freebsd.org/cgi/man.cgi?find%281%29 (appena confermato su un'installazione di FreeBSD 11)
— phk,

@PeterCordes Lo stesso per NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) e OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ). L'ultimo non supporta -quit/ -exitaffatto però.
— phk,

5

Puoi far trovare a run una nuova shell nella directory che trova.

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

, dopo di che la directory corrente sarà quella che contiene un file chiamato Fedora. ;)

Ovviamente questo fa qualcosa di simile a quello che vuoi se stai digitando i comandi in modo interattivo.


4

Con zsh:

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

a cdnella directory prima (in ordine alfabetico) che contiene un file chiamato Fedora.

  • **: qualsiasi livello di directory (le directory nascoste sono omesse per impostazione predefinita, utilizzare il Dqualificatore glob per includerle)
  • [1]: solo il primo
  • :h: modificatore di testa : prendi il nome dir.

Contrariamente a cd "$(find ...)", funziona anche se il nome della directory termina con un carattere di nuova riga. Un altro vantaggio è che riceverai un messaggio di errore senza corrispondenza quando non esiste una directory corrispondente (mentre nella maggior parte delle shell cd ""non farebbe nulla in silenzio).

Uno svantaggio è che dovrebbe strisciare per intero /media/storageprima di tornare.


In bash, cdcon più arg, guarda comunque solo il primo arg, quindi cd $(dirname /media/storage/**/Fedora)funzionerebbe (con shopt -s globstar) se non ci sono spazi nel percorso. Per farlo correttamente citato, credo che un array di bash è più facile: target=(/media/storage/**/Fedora); cd "${target%/*}". Ma a quel punto sarebbe stato più veloce utilizzare il mouse per copiare / incollare l'output di ricerca anziché elaborarlo interattivamente.
— Peter Cordes,

2
@PeterCordes, molte dirnameimplementazioni non accettano più di un argomento. Nota che non sono spazi , sono tutti i caratteri attualmente presenti $IFS(spazio, tabulazione e nuova riga di default) e caratteri jolly. Si noti che se la bash's cdaccetteranno più di un argomento dipende da come è stato compilato ( CD_COMPLAINSin config-top.h). Si può immaginare che le versioni future di basheventualmente implementeranno anche la funzione arg due come in zsh.
— Stéphane Chazelas,

Grazie. Ho appena guardato la manpage del nomname di coreutils GNU. La versione di dirname è comunque terribile; L'ho menzionato solo come qualcosa che potresti provare interattivamente nel caso funzionasse. La mia versione basata su array non presenta alcuno di questi problemi, poiché si "${target%*/}"espande solo al primo elemento dell'array (con lo /Fedorastripped). Penso che la versione sia completamente robusta rispetto a tutti i possibili caratteri nel percorso.
— Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.