web-dev-qa-db-fra.com

Utilisation de connecteurs après la commande find

Je veux que mon bash imprime 'trouvé' seulement si quelque chose est trouvé, en utilisant la commande find. Mais utiliser && n’aide en rien: même si rien n’est trouvé, je reçois l’impression "trouvé". Exemple:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found
10
Josef Klimuk

Vous pouvez créer find lui-même imprimer found:

find . -name xac -printf "found\n" -quit

Le -quit fera findquitter après le premier match , donc found n'est imprimé qu'une fois au maximum.

Sur un thread similaire sous Unix et Linux ( (make find fail si rien n'a été trouvé ), j'ai utilisé grep -qz pour renvoyer un statut de sortie non nul si find ne trouvait rien:

find /some/path -print0 -quit | grep -qz .

Ce que vous pouvez utiliser pour construire des commandes composées en utilisant && ou if:

find /some/path -print0 -quit | grep -qz . && echo found
18
muru

réponse de mur est approprié et bien adapté aux cas où nous voulons imprimer quelque chose si un fichier est trouvé. Dans le cas général où nous souhaitons exécuter une commande externe, telle que echo, nous pourrions utiliser le drapeau -exec.

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

La partie {} transmet le nom de fichier à la commande entre -exec et \; en tant qu'arguments. Notez que \ avant ; - il empêche Shell de l’interpréter de manière erronée ; dans le point-virgule de fermeture de Shell, signifiant la fin de la commande, mais Shell le traite comme un texte à transmettre à la commande find et pour trouver une commande, elle sert de fermeture aux arguments de -exec flag.


Pour construire des conditions de type if found do this; else do that, nous pourrions utiliser les commandes Substance $() et test (alias [):

$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                              
not found

$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"                                                                                                  
found

Adressant le commentaire de Dan

Dan dans le commentaires a demandé:

L'écho "j'ai trouvé {}" ne serait-il pas meilleur que l'écho "j'ai trouvé" {}? Peut-être que pour echo ça va, mais si quelqu'un copie la commande et remplace echo par une autre commande, il peut avoir un problème

Comprenons d'abord le problème. Généralement, dans les shells, il existe un concept de fractionnement de Word, ce qui signifie que les variables non entre guillemets et les paramètres de position seront développés et traités séparément. Par exemple, si vous avez la variable var et qu'elle contient hello world text, lorsque vous faites touch $var, le shell le décomposera en deux éléments distincts: hello et world et touch comprendront que vous essayez créer 2 fichiers séparés; si vous faites touch "$var", alors Shell traitera hello world comme une unité et touch ne créera qu'un seul fichier. Il est important de comprendre que cela se produit uniquement en raison du fonctionnement des coquilles.

En revanche, find ne souffre pas d'un tel comportement, car les commandes sont traitées par find et exécutées par execvp() appel système. Il n'y a donc pas de shell impliqué. Bien que les accolades aient une signification particulière dans les shells, car elles apparaissent au milieu de la commande find et non au début, elles n’ont aucune signification particulière pour Shell dans ce cas. Voici un exemple. Créons quelques noms de fichiers difficiles et essayons de les passer en tant qu'argument à la commande stat.

$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt

$ find -type f -exec stat -c "%F" {} \; -print                                                                                                                         
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt

Comme vous pouvez le constater, stat reçoit parfaitement les noms de fichiers difficiles avec find, ce qui est l’une des principales raisons pour lesquelles il est recommandé de l’utiliser dans les scripts portables, et particulièrement utile lorsque vous parcourez une arborescence de répertoires et que vous souhaitez utiliser des noms de fichiers qui puissent potentiellement avoir des caractères spéciaux en eux. Par conséquent, il n'est pas nécessaire de citer des accolades pour les commandes exécutées dans find.

C'est une autre histoire quand Shell intervient. Parfois, vous devez utiliser un shell pour traiter le nom de fichier. Dans ce cas, la citation importera, mais il est important de réaliser que ce n’est pas le problème de la découverte: c’est le shell qui effectue le fractionnement de Word.

$ find -type f -exec bash -c "stat {}" sh \;   
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory

Ainsi, lorsque nous citerons dans Shell , cela fonctionnera. Mais là encore, c’est important pour Shell et non pas find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
13