Lorsque vous essayez d'écrire la sortie standard d'un script Python dans un fichier texte (python script.py > log
), le fichier texte est créé au démarrage de la commande, mais le contenu réel n'est écrit qu'à la fin du script Python. Par exemple:
script.py:
import time
for i in range(10):
print('bla')
time.sleep(5)
imprime sur stdout toutes les 5 secondes lorsqu'il est appelé avec python script.py
, mais quand j'appelle python script.py > log
, la taille du fichier journal reste nulle jusqu'à la fin du script. Est-il possible d'écrire directement dans le fichier journal, de manière à pouvoir suivre la progression du script (par exemple en utilisant tail
)?
MODIFIER Il s'avère que python -u script.py
fait l'affaire, je ne connaissais pas la mise en mémoire tampon de stdout.
Cela se produit car normalement lorsque le processus STDOUT est redirigé vers autre chose qu'un terminal, la sortie est mise en mémoire tampon dans un tampon de taille spécifique au système d'exploitation (peut-être 4k ou 8k dans de nombreux cas). Inversement, lors de la sortie vers un terminal, STDOUT sera mis en mémoire tampon de ligne ou pas du tout, donc vous verrez la sortie après chaque \n
Ou pour chaque caractère.
Vous pouvez généralement modifier la mise en mémoire tampon STDOUT avec l'utilitaire stdbuf
:
stdbuf -oL python script.py > log
Maintenant, si vous tail -F log
, Vous devriez voir chaque sortie de ligne immédiatement lorsqu'elle est générée.
Alternativement, un rinçage explicite du flux de sortie après chaque impression devrait obtenir le même résultat. Il semble que sys.stdout.flush()
devrait y parvenir en Python. Si vous utilisez Python 3.3 ou plus récent, la fonction print
possède également un mot clé flush
qui fait ceci: print('hello', flush=True)
.
Cela devrait faire le travail:
import time, sys
for i in range(10):
print('bla')
sys.stdout.flush()
time.sleep(5)
Comme Python tamponnera le stdout
par défaut, ici j'ai utilisé sys.stdout.flush()
pour vider le tampon.
Une autre solution serait d'utiliser le commutateur -u
(Sans tampon) de python
. Donc, ce qui suit fera aussi:
python -u script.py >> log
Une variation sur le thème de l'utilisation de la propre option de python pour une sortie sans tampon serait d'utiliser #!/usr/bin/python -u
comme première ligne.
Avec #!/usr/bin/env python
cet argument supplémentaire ne fonctionnera pas, donc alternativement, on pourrait exécuter PYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt
ou faites-le en deux étapes:
$ export PYTHONUNBUFFERED=1
$ ./myscript.py
Vous devez réussir flush=True
à la fonction print
:
import time
for i in range(10):
print('bla', flush=True)
time.sleep(5)
Selon la documentation, par défaut, print
n'applique rien sur le vidage:
La sortie du tampon est généralement déterminée par fichier, mais si l'argument de mot clé
flush
est vrai, le flux est vidé de force.
Et la documentation des strems de sys
dit:
Lorsqu'ils sont interactifs, les flux standard sont tamponnés en ligne. Sinon, ils sont mis en mémoire tampon comme des fichiers texte normaux. Vous pouvez remplacer cette valeur avec le
-u
option de ligne de commande.
Si vous êtes coincé avec une ancienne version de python vous devez appeler la méthode flush
de la sys.stdout
stream:
import sys
import time
for i in range(10):
print('bla')
sys.stdout.flush()
time.sleep(5)