Dans un script bash, je voudrais capturer la sortie standard d'une longue ligne de commande ligne par ligne, afin qu'ils puissent être analysés et signalés pendant que la commande initiale est toujours en cours d'exécution. Voici la manière compliquée que j'imagine de le faire:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Je voudrais savoir s'il existe un moyen plus simple de le faire.
MODIFIER:
Afin de clarifier ma question, je vais ajouter ceci. Le longcommand
affiche son état ligne par ligne une fois par seconde. Je voudrais attraper la sortie avant la longcommand
fin.
De cette façon, je peux potentiellement tuer le fichier longcommand
s'il ne fournit pas les résultats attendus.
J'ai essayé:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Mais whatever
(par exemple echo
) ne s'exécute qu'une fois longcommand
terminé.
Réponses:
Il suffit de diriger la commande dans une
while
boucle. Il y a un certain nombre de nuances à cela, mais fondamentalement (dansbash
ou n'importe quel shell POSIX):L'autre problème principal avec cela (autre que le
IFS
contenu ci-dessous) est lorsque vous essayez d'utiliser des variables de l'intérieur de la boucle une fois qu'elle est terminée. En effet, la boucle est en fait exécutée dans un sous-shell (juste un autre processus shell) à partir duquel vous ne pouvez pas accéder aux variables (elle se termine également lorsque la boucle le fait, à quel point les variables ont complètement disparu. Pour contourner ce problème, tu peux faire:L'exemple de Hauke de la mise
lastpipe
enbash
est une autre solution.Mise à jour
Pour vous assurer que vous traitez la sortie de la commande «en temps réel», vous pouvez utiliser
stdbuf
pour définir le processus «stdout
pour qu'il soit mis en mémoire tampon de ligne.Cela configurera le processus pour écrire une ligne à la fois dans le canal au lieu de mettre en mémoire tampon interne sa sortie dans des blocs. Sachez que le programme peut modifier lui-même ce paramètre en interne. Un effet similaire peut être obtenu avec
unbuffer
(une partie deexpect
) ouscript
.stdbuf
est disponible sur les systèmes GNU et FreeBSD, il n'affecte que lastdio
mise en mémoire tampon et ne fonctionne que pour les applications non setuid, non setgid qui sont liées dynamiquement (car il utilise une astuce LD_PRELOAD).la source
IFS=
n'est pas nécessaire dansbash
, j'ai vérifié cela après la dernière fois.line
(auquel cas le résultat est inséré$REPLY
sans les espaces de début et de fin coupés). Essayez:echo ' x ' | bash -c 'read line; echo "[$line]"'
et comparez avececho ' x ' | bash -c 'IFS= read line; echo "[$line]"'
ouecho ' x ' | bash -c 'read; echo "[$REPLY]"'
la source