J'ai un petit script, appelé quotidiennement par crontab à l'aide de la commande suivante:
/homedir/MyScript &> some_log.log
Le problème avec cette méthode est que some_log.log n'est créé qu'après la fin de MyScript. Je voudrais vider la sortie du programme dans le fichier pendant son exécution pour pouvoir 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 appelle dans le cadre du script écriront et afficheront individuellement la sortie à chaque fois qu'elles le voudront. Votre question est donc de savoir comment forcer le vidage des commandes du script bash, et cela dépend de ce qu'elles sont.
J'ai trouvé une solution à ceci ici . En utilisant l'exemple de l'OP, vous exécutez essentiellement
stdbuf -oL /homedir/MyScript &> some_log.log
puis le tampon est vidé après chaque ligne de sortie. Je combine souvent cela avec Nohup
pour exécuter des travaux longs sur une machine distante.
stdbuf -oL Nohup /homedir/MyScript &> some_log.log
Ainsi, votre processus ne sera pas annulé lorsque vous vous déconnecterez.
script -c <PROGRAM> -f OUTPUT.txt
La clé est -f. Citation du script homme:
-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 <PROGRAM> -f OUTPUT.txt
Vous pouvez utiliser tee
pour écrire dans le fichier sans vidage.
/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
Ce n'est pas une fonction de bash
, car tout ce que le shell fait est d'ouvrir le fichier en question puis de transmettre le descripteur de fichier comme sortie standard du script. Ce que vous devez faire, c'est vous assurer que la sortie est vidée de votre script plus souvent que vous ne l'êtes actuellement.
En Perl par exemple, cela pourrait être accompli en définissant:
$| = 1;
Voir perlvar pour plus d'informations à ce sujet.
Est-ce que cela aiderait?
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
Ceci affichera immédiatement les entrées uniques de access.log
http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html
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 constatez 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 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 Shell a gelé pour moi après. En cherchant la cause, j'ai trouvé ces gros avertissements rouges "ne pas utiliser dans des shells non interactifs" dans page de manuel de script :
script
est principalement conçu pour les sessions de terminal interactives. Quand stdin n'est pas un terminal (par exemple:echo foo | script
), puis le La session peut se bloquer, car le shell interactif dans le script session rate EOF etscript
n'a aucune idée du moment de fermer la session . Voir la section NOTES pour plus d'informations.
Vrai. script -c "make_hay" -f /dev/null | grep "needle"
gelait le Shell pour moi.
Pays à l'avertissement, je pensais que echo "make_hay" | script
passera un EOF, alors j'ai essayé
echo "make_hay; exit" | script -f /dev/null | grep 'needle'
et ça a fonctionné!
Notez les avertissements dans la page de manuel. Cela peut ne pas fonctionner pour vous.
Comment vient de voir ici le problème est que vous devez attendre que les programmes que vous exécutez à partir de votre script finissent leur travail.
Si, dans votre script, vous exécutez un programme dans background, 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 des programmes dans background (&
), vous pouvez wait qu'ils se terminent avant de quitter le script. Pour avoir une idée de son fonctionnement, voyez 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
# ...
Étant donné que wait
fonctionne avec des travaux aussi bien qu'avec des nombres PID
, une solution peu fiable devrait être de mettre à la fin du script
for job in `jobs -p`
do
wait $job
done
La situation est plus difficile si vous exécutez quelque chose qui exécute autre chose en arrière-plan, car vous devez rechercher et attendre (si c'est le cas) la fin de tous les processus child: par exemple, si vous exécutez un démon ce n'est probablement pas le cas d'attendre que ça se termine :-).
Remarque:
wait $ {!} signifie "attendre que le dernier processus d'arrière-plan soit terminé", 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 wait
:
Syntax
wait [n ...]
Key
n A process ID or a job specification
l'alternative à stdbuf est awk '{print} END {fflush()}'
J'aimerais qu'il y ait une bash intégrée pour le faire . Normalement, cela ne devrait pas être nécessaire, mais avec les anciennes versions, il pourrait y avoir des bugs de synchronisation bash sur les descripteurs de fichiers.