web-dev-qa-db-fra.com

Pourquoi utiliser DirName dans la commande de recherche donne des points pour chaque match?

J'utilise la recherche d'une tâche et j'ai remarqué que lorsque je fais quelque chose comme ça:

find `pwd` -name "file.ext" -exec echo $(dirname {}) \;

cela vous donnera des points uniquement pour chaque match. Lorsque vous remplacez dirname avec basename dans cette commande, vous obtenez les noms de chemin complets. Suis-je vissé quelque chose ici ou est-ce que ce comportement attendu? Je suis habitué à basename vous donnant le nom du fichier (dans ce cas file.ext) et dirname vous donnant le reste du chemin.

33
temp2290

Considérez le script suivant:

#!/bin/sh
set -x
find `pwd` -name "file.ext" -exec echo $(dirname {}) \;

set -x Montre comment l'expansion fonctionne et quelle est la commande finale. Lorsqu'il est exécuté, il donne la sortie suivante:

++ pwd
++ dirname '{}'
+ find /home/kibab -name file.ext -exec echo . ';'

Donc, la première chose qui est étendue est le pwd. Deuxièmement, c'est $(dirname {}). Le résultat de ces deux commandes est ensuite tombé dans la commande de recherche. Ainsi, vous indiquez à trouver -exec echo ., Vous voyez donc la sortie attendue.

Lorsque vous remplacez basename pour dirname, l'expansion prend toujours des endroits, mais les résultats de l'expansion sont différents:

  1. pwd est étendu à la voie actuelle. Dans mon exemple ci-dessus, le résultat est /home/kibab
  2. basename {} Est exécuté. Le résultat de cette commande est {}.
  3. La commande de recherche est exécutée avec les substitutions ci-dessus en place. La commande finale exécutée ressemble à ceci:

    find /home/kibab -name '*.png' -exec echo '{}' ';'

Lors de l'inspection de la commande ci-dessus, vous remarquerez que la commande désormais tout simplement tout le dossier de l'ECHO.

Peut-être que tu veux quelque chose comme ça?

find `pwd` -name "file.ext" -printf "%f\n"
28
Kaleb Pederson

Donc, le problème est que $ (...) ou `...` commence une nouvelle coquille avant de faire le remplacement.

Pensez à utiliser Bash -C:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \;

Cela renomme n'importe quelle icône sur un repo git à une forme plus standard.

Ici {} est remplacé avant d'exécuter quoi que ce soit, le problème est parti.

Pour cet exemple, TMTOWTDI, mais j'essaie de garder cela simple afin que vous puissiez commencer ce que vous avez vraiment besoin de faire.

25
albfan

vous n'avez pas à appeler DirName () pour chaque fichier trouvé. avec GNU trouver, vous pouvez utiliser -printf et c'est plus rapide de cette façon

find /path -type f -iname "*.ext" -printf "%h\n"
8
ghostdog74

$(dirname {}) est évalué par la coque avant d'être transmis à find. Le résultat de cette évaluation est ., Vous devez donc simplement dire find d'exécuter echo . Pour chaque fichier qu'il trouve.

basename {} Évalue à {}, Donc avec $(basename {}) substitué pour $(dirname {}), find exécutera echo {} Pour chaque déposer. Cela se traduit par le nom complet de chaque fichier étant écho.

Si vous souhaitez émettre le résultat de dirname pour chaque fichier trouvé, vous pouvez omettre le echo:

find `pwd` -name "file.ext" -exec dirname {} \;
6
Phil Ross

Il vous montre les points, car la substitution de processus est évaluée avant que la commande soit réellement exécutée. Vous devez donc transmettre votre commande dans une instance de shell distincte.

Quant à la solution de contournement, utilisez la syntaxe suivante:

find $PWD -name "file.ext" -exec sh -c 'echo $(dirname {})' ';'

Cependant, le moyen le plus simple d'imprimer ou d'exécuter quelque chose dans chaque répertoire est de -execdir, par exemple.:

find . -name "file.ext" -execdir pwd ';'
5
kenorb

Je ne sais pas pourquoi vous obtenez cela, mais essayez ceci:

find `pwd` -name file.ext |xargs -l1 dirname
4
Paul Tomblin

C'est parce que find imprime les chemins par rapport au chemin qu'il effectue. Si vous avez essayé cette recherche de / vous obtiendrez `` pwd\ Pour chaque chemin.

0
pajton