J'ai a.sh qui appelle un b.sh :
. "b.sh" 2>&1 | tee -a "log.txt" & wait $! xxx
comment puis-je écrire une condition qui détecte quand b.sh ne produit pas log.txt pendant un certain temps, puis exécuter wait $!
3 Réponses :
. "b.sh" 2>&1 | tee -a "log.txt" &
child=$!
# loop while child process exists
while kill -0 "$child" 2>/dev/null; then
# get first length
if [[ -z "$len1" ]]; then
len1=$(wc log.txt)
fi
# sleep for a certain time
sleep 1
# get length of file after 1 second
len2=$(wc log.txt)
# compare lengths
if [ "$len1" == "$len2" ]; then
echo "Och my! File log.txt did not change in 1 second"
break
else
echo "All good! File log.txt did change in 1 second"
fi
# len1 becomes len2
len1=$len2;
fi
Vous pourriez faire:
#!/bin/bash
./b.sh 2>&1 | { while read -t 3 line; do
echo "$line" >> log.txt; done; pkill -g 0; } &
wait $!
Notez que dans votre exemple, votre script n'appelle pas b.sh, mais le sourit. Cette solution appelle b.sh. Cela semble plus propre, car la lecture de la sortie d'un script source est un comportement vraiment étrange.
Mais notez que si b.sh appelle un programme de longue durée qui génère beaucoup de sortie mais le fait lentement, vous rencontrerez sans aucun doute des problèmes de mise en mémoire tampon. Le programme de longue durée mettra très probablement en mémoire tampon sa sortie, donc bien qu'il génère périodiquement des données dans ses tampons internes, la read dans la boucle while ne le verra pas et peut expirer prématurément.
Sujet assez ancien mais j'ai fait un mélange de toutes les solutions suggérées pour répondre à mon besoin et je pense
#!/bin/bash
set -e
rm -rf log.txt
touch log.txt
rm -rf finish
./"b.sh" > log.txt 2>&1 && touch finish &
process_to_keep=$!
{ tail -f log.txt | while read -t 3 line && kill -0 "$process_to_keep" 2>/dev/null; do
echo "$line"
done;
if [ -e finish ]; then
echo "finish properly"
else
if kill -0 "$process_to_keep" 2>/dev/null; then
echo "no output after 3s"
kill $process_to_keep 2>/dev/null
else
echo "process not alive anymore"
fi
exit 1
fi; } &
process_to_wait=$!
wait $process_to_keep
echo "done" >> log.txt
wait $process_to_wait
echo "cleaning temporary files"
rm -rf finish
rm -rf log.txt
Ce script s'arrêtera si le script b se termine à tout moment (sans aucun délai ce qui était le cas avec une autre solution) et il se terminera également s'il n'y a pas de sortie pendant 3s avec un message correct dans la console.
Je pense que cette solution ne fonctionne pas correctement sur macOS.
Que signifie «traverser»? Utilisez une méthode d'interrogation - obtenir la longueur du fichier, attendre une seconde, obtenir la longueur du fichier - si les longueurs sont identiques, cela signifie que rien n'a été produit pendant un certain temps.
C'est risqué. Si b.sh génère un caractère toutes les 15 secondes, il est très probable que
teene verra aucune donnée pendant plus de 4 heures. (En raison de la mise en mémoire tampon) (Ceci est moins probable si b.sh est un shell et appelle probablement des programmes courts qui écrivent la sortie et se terminent, mais tout à fait une possibilité.) Comment allez-vous gérer cela?Mais
bashinterne read s » a une-toption vous pouvez utiliser.