Comment utiliser `find` pour aller dans le répertoire de ce fichier

11

Je veux trouver un fichier puis entrer dans le répertoire qui le contient. J'ai essayé find /media/storage -name "Fedora" | xargs cdmais bien sûr, j'ai l' is not a directoryerreur.

Comment puis-je entrer son répertoire parent avec une commande d'une ligne?

Hrvoje T
la source
1
Et si plusieurs fichiers proviennent de plusieurs emplacements?
Sergiy Kolodyazhnyy
@Serg Im recherche un fichier Fedora * .iso et je sais qu'il n'y en a qu'un. S'il y en avait plus d'un, il entrerait dans le premier direcotry, je suppose
Hrvoje T
En bash avec shopt -s globstar, vous pourriez cd /media/storage/**/Fedora, mais cela n'arrête pas d'évaluer le glob lors de la première correspondance (donc c'est plus lent que la solution de steeldriver. Pour une utilisation interactive, ce que je ferais normalement est d'atteindre la souris et de copier / coller le nom du répertoire, (et alt + backspace si nécessaire pour supprimer les composants du chemin de fuite que je ne voulais pas), mais si vous faites beaucoup de choses, je suppose qu'une fonction shell pourrait valoir la peine d'être créée.
Peter Cordes
1
BTW, xargs cdne peut pas fonctionner. cdne peut fonctionner que comme un shell intégré, car il doit modifier le contexte du shell lui-même. Il n'y a aucun moyen qu'un xargsprocessus enfant puisse faire cela. IDK si c'est ce que vous vouliez dire "bien sûr", ou si le chemin qui findimprime contient des espaces, qui sont divisés par xargs puisque vous ne l'avez pas utilisé -d \nou quoi que ce soit. Ou find -exec {} \;.
Peter Cordes
note: vous ne pouvez pas courir cdcomme ça. cdest un bash intégré, s'il cds'agissait d'une commande distincte, il changerait (son propre) répertoire, puis quitterait (vous ramenant au shell, qui est dans le même état que précédemment, aucun changement de répertoire).
ctrl-alt-delor

Réponses:

14

Au moins si vous avez GNU find, vous pouvez utiliser -printf '%h'pour obtenir le répertoire

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

Vous pourriez donc probablement faire

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

Le -quitdevrait empêcher plusieurs arguments cddans le cas où plus d'un fichier correspond.

tournevis
la source
1
-quitn'est également pas nécessairement pris en charge. Dans NetBSD, cela s'appelle -exit, voir unix.stackexchange.com/a/62883/117599
phk
2
S'il n'y a pas printf, pourriez-vous faire -exec dirname à la place?
Guy
@Guy bonne idée oui, il semble que cela devrait fonctionner aussi
steeldriver
6

Semblable à la solution de Steeldriver mais en utilisant -execdir(si votre findsupport, comme GNU ou FreeBSD find) en combinaison avec pwd:

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

-quitest facultatif dans le cas où il n'y a qu'un seul résultat et en explorant l'ensemble du répertoire, il n'y a pas de problème. Sur NetBSD c'est -exitet sur OpenBSD ça n'existe pas.

phk
la source
Et à quoi ça sert \;?
Hrvoje T
1
@HrvojeT Tout comme -execil indique findla fin des paramètres de la commande à exécuter. Mais puisque nous voulons appeler pwdsans paramètres ici, nous mettons le \;droit après.
phk
Existe-t-il des findimplémentations qui prennent en charge execdir mais pas -printf %h? Cela me semble peu probable. Malheureusement, ni l'un ni l'autre n'est requis par POSIX: /
Peter Cordes
1
@PeterCordes FreeBSD's find: freebsd.org/cgi/man.cgi?find%281%29 (Je viens de le confirmer sur une installation de FreeBSD 11).
phk
@PeterCordes Idem pour NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) et OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ). Latter ne prend pas en charge -quit/ pas -exitdu tout.
phk
5

Vous pouvez faire exécuter find un nouveau shell dans le répertoire qu'il trouve.

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

, après quoi le répertoire courant sera celui qui contient un fichier nommé Fedora. ;)

Évidemment, cela ne fait que ressembler à ce que vous voulez si vous tapez des commandes de manière interactive.

BenGoldberg
la source
4

Avec zsh:

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

à cddans le premier répertoire (par ordre alphabétique) qui contient un fichier appelé Fedora.

  • **: n'importe quel niveau de répertoires (les répertoires cachés sont omis par défaut, utilisez le Dqualificatif glob pour les inclure)
  • [1]: seulement le premier
  • :h: modificateur de tête : prenez le dirname.

Contrairement à cd "$(find ...)", cela fonctionne également si le nom du répertoire se termine par un caractère de nouvelle ligne. Un autre avantage est que vous obtiendrez un message d'erreur sans correspondance lorsqu'il n'y a pas de répertoire correspondant (alors que dans la plupart des shells, cd ""cela ne ferait rien en silence).

Un inconvénient est qu'il ramperait tout /media/storageavant de revenir.

Stéphane Chazelas
la source
En bash, cdavec plusieurs arguments ne regarde de toute façon que le premier argument, donc cd $(dirname /media/storage/**/Fedora)fonctionnerait (avec shopt -s globstar) s'il n'y a pas d'espaces dans le chemin. Pour l' obtenir cité correctement, je pense qu'un tableau bash est plus facile: target=(/media/storage/**/Fedora); cd "${target%/*}". Mais à ce stade, il aurait été plus rapide d'utiliser la souris pour copier / coller la sortie de recherche au lieu de proposer cela de manière interactive.
Peter Cordes
2
@PeterCordes, de nombreuses dirnameimplémentations n'acceptent pas plus d'un argument. Notez que ce ne sont pas des espaces , c'est n'importe quel caractère actuellement $IFS(espace, tabulation et saut de ligne par défaut) et des caractères génériques. Notez que si bashl » cdacceptent plus d'un argument dépend de la façon dont il a été compilé ( CD_COMPLAINSen config-top.h). On peut imaginer que les futures versions de bashéventuellement implémenteront également la fonction deux arg comme dans zsh.
Stéphane Chazelas
Merci. Je viens de regarder la page de manuel GNU coreutils dirname. La version dirname est terrible de toute façon; Je l'ai seulement mentionné comme quelque chose que vous pourriez essayer de manière interactive au cas où cela fonctionnerait. Ma version basée sur un tableau ne souffre d'aucun de ces problèmes, car elle ne "${target%*/}"s'étend qu'au premier élément du tableau (avec le /Fedoradépouillé). Je pense que cette version est entièrement robuste contre tous les caractères possibles dans le chemin d'accès.
Peter Cordes du