Forcer le vidage de la sortie dans un fichier pendant que le script bash est toujours en cours d’exécution

J’ai un petit script, appelé quotidiennement par crontab en utilisant la commande suivante:

/homedir/MyScript &> some_log.log 

Le problème avec cette méthode est que some_log.log est créé uniquement après la fin de MyScript. Je voudrais vider la sortie du programme dans le fichier pendant qu’il fonctionne afin que je puisse faire des choses comme

 tail -f some_log.log 

et suivre les progrès, etc.

    bash lui-même n’écrira jamais de sortie dans votre fichier journal. Au lieu de cela, les commandes qu’il invoque dans le cadre du script écrivent individuellement et sortent chaque fois qu’elles le souhaitent. Donc, votre question est vraiment de savoir comment forcer les commandes dans le script bash à vider, et cela dépend de ce qu’elles sont.

    J’ai trouvé une solution à cela ici . En utilisant l’exemple de l’OP, vous exécutez essentiellement

    stdbuf -oL /homedir/MyScript &> some_log.log

    et puis le tampon est vidé après chaque ligne de sortie. Je combine souvent cela avec nohup pour exécuter de longs travaux sur une machine distante.

    stdbuf -oL nohup /homedir/MyScript &> some_log.log

    De cette façon, votre processus n’est pas annulé lorsque vous vous déconnectez.

    script -c -f OUTPUT.txt

    La clé est -f. Citation du script man:

      -f, --flush Flush output after each write. This is nice for telecooperation: one person does `mkfifo foo; script -f foo', and another can supervise real-time what is being done using `cat foo'. 

    De fonctionner en arrière-plan:

     nohup script -c  -f OUTPUT.txt 

    Vous pouvez utiliser tee pour écrire dans le fichier sans avoir besoin de vider.

     /homedir/MyScript 2>&1 | tee some_log.log > /dev/null 

    Ce n’est pas une fonction de bash , car tout ce que fait le shell est d’ouvrir le fichier en question, puis de passer le descripteur de fichier en tant que sortie standard du script. Ce que vous devez faire est de vous assurer que la sortie est extraite de votre script plus fréquemment que vous ne l’êtes actuellement.

    En Perl par exemple, cela pourrait être réalisé en définissant:

     $| = 1; 

    Voir perlvar pour plus d’informations à ce sujet.

    Serait-ce une aide?

     tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq 

    Cela affichera immédiatement des entrées uniques de access.log
    http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html

    Le problème vient du fait que vous devez attendre que les programmes que vous exécutez à partir de votre script aient terminé leurs travaux.
    Si dans votre script vous exécutez un programme en arrière-plan, vous pouvez essayer quelque chose de plus.

    En général, un appel à sync avant de quitter permet de vider les tampons du système de fichiers et peut aider un peu.

    Si dans le script vous démarrez certains programmes en arrière-plan ( & ), vous pouvez attendre qu’ils se terminent avant de quitter le script. Pour avoir une idée de son fonctionnement, vous pouvez voir ci-dessous

     #!/bin/bash #... some stuffs ... program_1 & # here you start a program 1 in background PID_PROGRAM_1=${!} # here you remember its PID #... some other stuffs ... program_2 & # here you start a program 2 in background wait ${!} # You wait it finish not really useful here #... some other stuffs ... daemon_1 & # We will not wait it will finish program_3 & # here you start a program 1 in background PID_PROGRAM_3=${!} # here you remember its PID #... last other stuffs ... sync wait $PID_PROGRAM_1 wait $PID_PROGRAM_3 # program 2 is just ended # ... 

    Comme wait fonctionne avec les jobs aussi bien qu’avec PID numéros PID , une solution paresseuse devrait être de mettre à la fin du script

     for job in `jobs -p` do wait $job done 

    Plus difficile est la situation si vous exécutez quelque chose qui exécute autre chose en arrière-plan parce que vous devez rechercher et attendre (si c’est le cas) la fin de tout le processus fils : par exemple, si vous exécutez un démon probablement pas attendre que ça se termine :-).

    Remarque:

    • wait $ {!} signifie “attendre la fin du dernier processus d’arrière-plan” où $! est le PID du dernier processus d’arrière-plan. Donc, mettre wait ${!} Juste après program_2 & équivaut à exécuter directement program_2 sans l’envoyer en arrière-plan avec &

    • De l’aide de l’ wait :

       Syntax wait [n ...] Key n A process ID or a job specification 

    La mise en mémoire tampon de la sortie dépend de la manière dont votre programme /homedir/MyScript est implémenté. Si vous trouvez que la sortie est mise en mémoire tampon, vous devez la forcer dans votre implémentation. Par exemple, utilisez sys.stdout.flush () s’il s’agit d’un programme Python ou utilisez fflush (stdout) s’il s’agit d’un programme C.

    Merci @user3258569 , le script est peut-être la seule chose qui fonctionne dans busybox !

    Le coquillage me gelait après. En cherchant la cause, j’ai trouvé ces gros avertissements rouges “ne pas utiliser dans un shell non interactif” dans la page de manuel du script :

    script est principalement conçu pour les sessions de terminal interactives. Lorsque stdin n’est pas un terminal (par exemple: echo foo | script ), la session peut être bloquée, car le shell interactif de la session de script manque EOF et le script n’a aucune idée de la date de fermeture de la session. Voir la section NOTES pour plus d’informations.

    Vrai. script -c "make_hay" -f /dev/null | grep "needle" script -c "make_hay" -f /dev/null | grep "needle" était en train de geler la shell pour moi.

    Contre la mise en garde, je pensais que echo "make_hay" | script echo "make_hay" | script passera un EOF, donc j’ai essayé

     echo "make_hay; exit" | script -f /dev/null | grep 'needle' 

    et ça a marché!

    Notez les avertissements dans la page de manuel. Cela peut ne pas fonctionner pour vous.

    Je ne sais pas si cela fonctionnerait, mais qu’en est-il de l’appel de la sync ?

    J’ai eu ce problème avec un processus en arrière-plan dans Mac OS X utilisant les StartupItems . Voici comment je le résous:

    Si je mytool sudo ps aux je peux voir que mytool est lancé.

    J’ai constaté que (en raison de la mise en mémoire tampon) lorsque Mac OS X est arrêté, mytool ne transfère jamais la sortie à la commande sed . Cependant, si sudo killall mytool , alors mytool transfère la sortie à la commande sed . Par conséquent, j’ai ajouté un cas d’ stop aux StartupItems exécutés lorsque Mac OS X est arrêté:

     start) if [ -x /sw/sbin/mytool ]; then # run the daemon ConsoleMessage "Starting mytool" (mytool | sed .... >> myfile.txt) & fi ;; stop) ConsoleMessage "Killing mytool" killall mytool ;; 

    bien comme ça ou pas c’est comme ça que fonctionne la redirection.

    Dans votre cas, la sortie (c’est-à-dire que votre script a terminé) de votre script a été redirigée vers ce fichier.

    Ce que vous voulez faire, c’est append ces redirections dans votre script.