Existe-t-il un moyen de forcer la commande find
à s'arrêter juste après avoir trouvé la première correspondance?
Avec GNU ou FreeBSD find
, vous pouvez utiliser le -quit
prédicat:
find . ... -print -quit
L'équivalent NetBSD find
:
find . ... -print -exit
Si tout ce que vous faites est d'imprimer le nom et en supposant que les noms de fichiers ne contiennent pas de caractères de nouvelle ligne, vous pouvez faire:
find . ... -print | head -n 1
Cela n'arrêtera pas find
après la première correspondance, mais peut-être, selon le timing et la mise en mémoire tampon lors de la deuxième correspondance ou (beaucoup) plus tard. Fondamentalement, find
se terminera par un SIGPIPE lorsqu'il essaiera de sortir quelque chose alors que head
sera 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 commande find
après le retour de head
. Les implémentations Bourne Shell et AT&T de ksh
(lorsqu'elles ne sont pas interactives) et yash
(uniquement si ce pipeline est la dernière commande d'un script) ne le feraient pas, le laissant s'exécuter 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 en:
(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 tout ce que vous feriez avec ce fichier).
Cela a pour effet secondaire de find
de renvoyer un statut de sortie reflétant le fait qu'il a été tué cependant.
En fait, en utilisant le signal SIGPIPE au lieu de SIGTERM (kill -s PIPE
au lieu de kill
) fera que certains shells seront plus silencieux sur cette mort (mais retourneront toujours un état de sortie différent de zéro).
find . -name something -print -quit
Met fin à la recherche après la première correspondance après l'avoir imprimée.
Mettre fin à la recherche après un nombre spécifique de correspondances et imprimer les résultats:
find . -name something -print | head -n 5
Étonnamment, head termine désormais la chaîne après 5 matchs, mais je ne sais pas comment ni pourquoi.
C'est très facile à tester. Laissez simplement rechercher a à la racine, ce qui entraînerait des milliers, voire plus de correspondances tout en prenant au moins une minute ou plus. Mais lorsqu'il est canalisé dans "head", "find" se terminera après la quantité spécifiée de lignes définie dans head (la tête par défaut affiche 10, utilisez "head -n" pour spécifier les lignes).
Notez que cela se terminera après que "head -n" atteindra le nombre de caractères de nouvelle ligne spécifié et donc 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 dans Bash. Cet exemple génère un anneau sur les fichiers du répertoire en cours. Lisez autant que vous voulez, puis 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 renvoie également s'il est 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 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 (peu importe cependant), tandis que si la recherche est longue, il épargnera à find d'imprimer un grand nombre de lignes inutiles.
cela fonctionne à la place avec la recherche de busybox, bien que depuis grep de busybox a également -m
ce n'est pas vraiment nécessaire
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
cela va cracher un message sur le processus de recherche ayant reçu le signal sigterm (généralement), mais cette sortie appartient au shell en cours d'exécution, pas à la commande find, donc elle ne dérange pas avec la sortie de la commande, ce qui signifie que les tuyaux ou les redirections ne produiront que la ligne correspond à trouver.