Existe-t-il un moyen de forcer la find
commande à s’arrêter juste après avoir trouvé le premier match?
Existe-t-il un moyen de forcer la find
commande à s’arrêter juste après avoir trouvé le premier match?
Réponses:
Avec GNU ou FreeBSD find
, vous pouvez utiliser le -quit
prédicat:
find . ... -print -quit
L' find
équivalent NetBSD :
find . ... -print -exit
Si vous ne faites qu'imprimer le nom, et en supposant que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne, vous pouvez procéder comme suit:
find . ... -print | head -n 1
Cela ne s'arrêtera pas find
après le premier match, mais éventuellement, en fonction du moment choisi et de la mise en mémoire tampon lors du deuxième match ou beaucoup (beaucoup) plus tard. Fondamentalement, find
se terminera par un SIGPIPE quand il essaie de sortir quelque chose alors qu'il head
est déjà parti car il a déjà lu et affiché la première ligne d'entrée.
Notez que tous les shells n'attendront pas cette find
commande après leur head
retour. Les implémentations de Bourne Shell et d’AT & T ksh
(non interactif) et yash
(seulement si ce pipeline est la dernière commande d’un script) ne le feraient pas, le laissant fonctionner en arrière-plan. Si vous préférez voir ce comportement dans n’importe quel shell, vous pouvez toujours changer ce qui précède pour:
(find . ... -print &) | head -n 1
Si vous faites plus qu'imprimer les chemins des fichiers trouvés, vous pouvez essayer cette approche:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(remplacez printf
par ce que vous feriez avec ce fichier).
Cela a pour effet secondaire de find
retourner un statut de sortie reflétant le fait qu'il a été tué cependant.
En fait, utiliser le signal SIGPIPE au lieu de SIGTERM ( kill -s PIPE
au lieu de kill
) fera que certains shells seront plus silencieux à propos de cette mort (mais renverront tout de même un statut de sortie non nul).
if [[ $(find ... -print -quit) ]]; then ...
Il teste simplement si rien n'est imprimé.
$(…)
partie entre guillemets au cas où vous n'utiliseriez que les crochets simples ( [ … ]
).
[
est une commande standard. Ce n'est pas tellement cette commande qui est horrible, mais la façon dont les obus Bourne-like analysent les lignes de commande. [[...]]
est une construction ksh qui a ses propres problèmes dans divers shells. Par exemple, jusqu'à récemment [[ $(...) ]]
, ne travaillait pas zsh
(vous aviez besoin de [[ -n $(...) ]]
). Sauf dans zsh
, vous avez besoin de guillemets [[ $a = $b ]]
, il y [[ =~ ]]
a des différences incompatibles entre les implémentations et même entre les versions de bash et plusieurs bugs dans certaines. Personnellement, je préfère [
.
...
? .
find . -name something -print -quit
Termine find après le premier match après l’avoir imprimé.
Mettez fin à la recherche après un nombre spécifique de correspondances et d’impression des résultats:
find . -name something -print | head -n 5
Curieusement, head termine maintenant la chaîne après 5 matchs, bien que je ne sache pas comment ni pourquoi.
C'est très facile à tester. Il suffit de laisser chercher une racine qui produirait des milliers, voire davantage de correspondances en prenant au moins une minute ou plus. Mais lorsque vous êtes connecté à "head", "find" se terminera après le nombre spécifié de lignes définies dans head (la tête par défaut indique 10, utilisez "head -n" pour spécifier des lignes).
Notez que cela se terminera lorsque "head -n" aura atteint le nombre de caractères de nouvelle ligne spécifié. Par conséquent, toute correspondance contenant plusieurs caractères de nouvelle ligne comptera en conséquence.
À des fins de divertissement, voici un générateur de recherche paresseux à Bash. Cet exemple génère un anneau sur les fichiers du répertoire en cours. Lire autant que vous voulez alors kill %+
(peut-être juste 1)
#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT
coproc x while :; do
find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
read -r _
printf '%s\0' "$x"
done
EOF
while
echo >&${x[1]}
IFS= read -rd '' -u "$x" 'files[n++]'
do
printf '%q ' "${files[@]}"
echo
sleep .2
done
grep retourne également si utilisé avec le drapeau -m
, donc avec
find stuff | grep -m1 .
il reviendra après la première ligne imprimée par find.
La différence entre ceci et ceci find stuff -print -quit | head -1
est que si la recherche est assez rapide, grep pourrait ne pas être en mesure d'arrêter le processus à temps (cela n'a pas vraiment d'importance), alors que si la recherche est longue, elle épargnera beaucoup d'impressions. lignes.
cela fonctionne à la place avec busybox find, bien que puisque busybox, grep dispose également de -m
cela, ce n'est pas vraiment nécessaire
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
cela crachera un message sur le processus de recherche ayant reçu le signal (généralement) sigterm, mais cette sortie appartient au shell en cours d'exécution, pas à la commande find, elle ne gâche donc pas le résultat de la commande, ce qui signifie que les tuyaux ou les redirections ne produiront que la ligne. assorti par trouver.