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
tee
ne 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
bash
interne read s » a une-t
option vous pouvez utiliser.