TheUnseen: La raison pour laquelle il se ferme après cinq résultats lorsqu'il est connecté à head -n 5 est parce que head se ferme après cinq résultats. Lorsque la tête sort de la conduite, le tuyau se ferme et envoie un signal au programme qui s'y connecte pour se terminer également. Désolé de ne pas vous répondre directement, apparemment, vous avez besoin de 50 points de réputation pour répondre.
Ruste
Réponses:
148
Avec GNU ou FreeBSD find, vous pouvez utiliser le -quitpré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 findaprè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, findse terminera par un SIGPIPE quand il essaie de sortir quelque chose alors qu'il headest 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 findcommande après leur headretour. 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 printfpar ce que vous feriez avec ce fichier).
Cela a pour effet secondaire de findretourner 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 PIPEau 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).
Dans le cas où quelqu'un aurait besoin de vérifier si un fichier correspond aux prédicats, s'arrêtant dès qu'on en trouve un dans Bash et GNU Find, vous pouvez le faire: if [[ $(find ... -print -quit) ]]; then ...Il teste simplement si rien n'est imprimé.
Tobia
@Tobia Mieux vaut mettre la $(…)partie entre guillemets au cas où vous n'utiliseriez que les crochets simples ( [ … ]).
phk
@phk Sauf que je n'utilise pas les crochets simples (parce qu'ils sont horribles), je n'ai donc pas besoin d'utiliser des guillemets.
Tobia
2
@Tobia, [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 [.
Stéphane Chazelas
c'est quoi ...? .
kyb
11
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.
J'ai également observé que ce programme se termine une fois que la tête est terminée avec son phénomène de sortie, mais pas de manière uniforme d'un shell à l'autre. Je pense que cela mérite sa propre question - heureusement pour bash, la réponse est déjà donnée par le comportement Bash: Head & Tail de StackOverflow avec le script bash . Cela me donne suffisamment d’informations pour conclure que la réponse du programme à SIGPIPE dépend de sa réponse à SIGPIPE, qu’il s’agisse de l’arrêt ou de la poursuite de l’exécution en arrière-plan.
Sage
Je voulais dire «entre * programmes * / coquilles», mais apparemment, unix.stackexchange.com préférerait que je consigne cela en tant que second commentaire plutôt que de me laisser éditer mon premier commentaire (il s'agit d'une décision de stratégie stackexchange, spécifique à un site). En outre, je vois maintenant que @Ruste a commenté cet effet en haut, ce qui ne m'a pas aidé initialement car je suis allé directement aux réponses ...
sage
2
À 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 -1est 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 -mcela, ce n'est pas vraiment nécessaire
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.
Réponses:
Avec GNU ou FreeBSD
find
, vous pouvez utiliser le-quit
prédicat:L'
find
équivalent NetBSD :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:
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'ilhead
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 leurhead
retour. Les implémentations de Bourne Shell et d’AT & Tksh
(non interactif) etyash
(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:Si vous faites plus qu'imprimer les chemins des fichiers trouvés, vous pouvez essayer cette approche:
(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 dekill
) fera que certains shells seront plus silencieux à propos de cette mort (mais renverront tout de même un statut de sortie non nul).la source
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 paszsh
(vous aviez besoin de[[ -n $(...) ]]
). Sauf danszsh
, 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[
....
? .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:
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.
la source
À 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)la source
grep retourne également si utilisé avec le drapeau
-m
, donc avecil 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écessairecela 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.
la source