Utilisation de connecteurs après la commande find

10

Je veux que mon bash n'imprime 'found' que si quelque chose est trouvé, en utilisant la commande find. Mais l'utilisation de && n'aide pas: même si je ne trouve rien, je suis imprimé. 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
Josef Klimuk
la source

Réponses:

18

Vous pouvez vous faire findimprimer found:

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

Le -quitfera find quitter après le premier match , foundest donc imprimé au maximum une fois.

Sur un fil similaire sur Unix et Linux ( make find échoue quand rien n'a été trouvé ), je grep -qzretournais un état de sortie non nul si je findne trouvais rien:

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

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

find /some/path -print0 -quit | grep -qz . && echo found
muru
la source
Je devais regarder ce moment. /some/pathindique où commencer à chercher, mais rien ne lui dit quoi chercher. Même chose dans votre réponse liée. Ce qui fonctionne pour moi, c'est find /some/path -name xac -print0 -quit | grep -qz . && echo found. Ai-je oublié quelque chose?
Joe
@Joe ce qui compte ici, c'est le -print0 -quit. Ce que vous mettez avant cela dépend de ce que vous voulez trouver. J'ai choisi de l'omettre ici.
muru
13

La réponse de muru est appropriée et bien adaptée aux cas où nous voulons imprimer quelque chose si un fichier est trouvé. Pour le cas général où nous voulons exécuter une commande externe, comme echo, nous pourrions utiliser -execflag.

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

La {}partie transmet le nom de fichier à la commande entre -execet \;comme arguments. Notez ce qui \précède ;- il empêche le shell de l'interpréter de manière erronée ; dans le shell fermant le point-virgule signifie la fin de la commande, mais lorsqu'il est échappé avec une barre oblique, le shell le traitera comme du texte littéral à passer à la findcommande et pour trouver la commande, il servira -execd'argument du drapeau de fermeture .


Pour construire des conditionnelles de ce if found do this; else do thattype, nous pourrions utiliser la sous-station de commande $()et la testcommande (aka [):

$ [ "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

Répondre au commentaire de Dan

Dan dans les commentaires demandait:

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

Comprenons d'abord le problème. Habituellement, dans les coquilles, il existe un concept de séparation des mots, ce qui signifie que les variables non cotées et les paramètres de position seront développés et traités comme des éléments distincts. Par exemple, si vous avez variables varet il contient du hello worldtexte, quand vous faites touch $varle shell décomposer en deux éléments distincts helloet worldet touchcomprendra que si vous essayez de créer 2 fichiers séparés; si vous le faites touch "$var", le shell sera traité hello worldcomme une seule unité et touchne créera qu'un seul fichier. Il est important de comprendre que cela se produit uniquement en raison du fonctionnement des obus.

En revanche, findne souffre pas d'un tel comportement, car les commandes sont traitées par findlui-même et exécutées par execvp()appel système, donc aucun shell n'est impliqué. Bien que les accolades aient une signification particulière dans les coquilles, car elles apparaissent au milieu de la findcommande et non au début, elles n'ont aucune signification particulière à coquiller dans ce cas. Voici un exemple. Créons quelques noms de fichiers difficiles et essayons de les passer comme argument à statcommander.

$ 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 voir, statreçoit parfaitement les noms de fichiers difficiles find, ce qui est l'une des principales raisons pour lesquelles il est recommandé pour une utilisation dans des scripts portables, et particulièrement utile lorsque vous parcourez l'arborescence de répertoires et que vous voulez faire quelque chose avec des noms de fichiers qui pourraient potentiellement avoir 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 lorsque Shell s'implique. Parfois, vous devez utiliser un shell pour traiter le nom de fichier. Dans ce cas, la citation importera en effet, mais il est important de réaliser que ce n'est pas le problème de la recherche - c'est le shell qui fait le fractionnement des mots.

$ 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

Donc, lorsque nous citons dans shell , cela fonctionnera. Mais encore une fois, c'est important pour shell, non find.

$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;                                                                                                                 
regular empty file
regular empty file
regular empty file
Sergiy Kolodyazhnyy
la source
Ce ne serait pas echo "I found {}"mieux que echo "I found " {}? Peut-être que pour l'écho, c'est bien, mais si quelqu'un copie la commande et remplace l'écho par une autre commande, il peut avoir un problème.
Dan
@Dan, le sujet était trop long pour être discuté dans les commentaires, j'ai donc modifié ma réponse. S'il vous plaît le voir
Sergiy Kolodyazhnyy
1
Merci de m'avoir enfin fait comprendre pourquoi ce point-virgule devait être là. Aussi, grande explication de la citation.
Joe
1
Je n'attendais pas autant de détails pour répondre à mon commentaire. J'apprécie beaucoup cette explication, merci!
Dan