SI on voulait vraiment ces données, je suggérerais de joindre le gdb débogueur à l'interpréteur python, arrêtant momentanément la tâche, appelant fsync(1)
(sortie standard ), détachez-vous de celui-ci (reprise du processus) et allez parcourir le fichier de sortie.
Regardez dans /proc/$(pidof python)/fd
pour voir les descripteurs de fichiers valides. $(pidof x)
renvoie le PID du processus nommé 'x
'.
# your python script is running merrily over there.... with some PID you've determined.
#
# load gdb
gdb
#
# attach to python interpreter (use the number returned by $(pidof python))
attach 1234
#
# force a sync within the program's world (1 = stdout, which is redirected in your example)
call fsync(1)
#
# the call SHOULD have returned 0x0, sync successful. If you get 0xffffffff (-1), perhaps that wasn't stdout. 0=stdin, 1=stdout, 2=stderr
#
# remove our claws from poor python
detach
#
# we're done!
quit
J'ai utilisé cette méthode pour modifier les répertoires de travail, modifier les paramètres à la volée... beaucoup de choses. Hélas, vous ne pouvez appeler que des fonctions définies dans le programme en cours d'exécution, fsync
fonctionne bien cependant.
(commande gdb 'info functions
' listera toutes les fonctions disponibles. Soyez prudent cependant. Vous opérez EN DIRECT sur un processus.)
Il y a aussi la commande peekfd
(trouvé dans psmisc
package sur Debian Jessie et autres) qui vous permettra de voir ce qui se cache dans les tampons d'un processus. Encore une fois, /proc/$(pidof python)/fd
vous montrera des descripteurs de fichiers valides à donner comme arguments à peekfd.
Si vous ne vous souvenez pas de -u
pour python, vous pouvez toujours préfixer une commande avec stdbuf
(en coreutils
, déjà installé) pour définir stdin/stdout/stderr sur unbuffered, line buffered ou block buffered comme vous le souhaitez :
stdbuf -i 0 -o 0 -e 0 python myscript.py > unbuffered.output
Bien sûr, man pages
sont vos amis, hé! peut-être qu'un alias pourrait être utile ici aussi.
alias python='python -u'
Maintenant, votre python utilise toujours -u
pour tous vos efforts en ligne de commande !
Assurez-vous d'abord que vous avez les symboles de débogage pour Python (ou au moins glibc). Sur Fedora, vous pouvez les installer avec :
dnf debuginfo-install python
Attachez ensuite gdb au script en cours d'exécution et exécutez les commandes suivantes :
[[email protected] ~]$ pidof python2
9219
[[email protected] ~]$ gdb python2 9219
GNU gdb (GDB) Fedora 7.7.1-13.fc20
...
0x00007fa934278780 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) call fflush(stdout)
$1 = 0
(gdb) call setvbuf(stdout, 0, 2, 0)
$2 = 0
(gdb) quit
A debugging session is active.
Inferior 1 [process 9219] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2, process 9219
Cela videra stdout et également désactiver la mise en mémoire tampon. Le 2
du setvbuf
call est la valeur de _IONBF
sur mon système. Vous devrez découvrir ce qu'il y a sur le vôtre (un grep _IONBF /usr/include/stdio.h
devrait faire l'affaire).
D'après ce que j'ai vu dans l'implémentation de PyFile_SetBufSize
et PyFile_WriteString
dans CPython 2.7, cela devrait fonctionner plutôt bien, mais je ne peux donner aucune garantie.
Il n'y a pas de solution à votre problème immédiat. Si votre script a déjà démarré, vous ne pouvez pas modifier le mode de mise en mémoire tampon après coup. Ce sont tous des tampons en mémoire et tout cela est configuré lorsque le script démarre, les descripteurs de fichiers sont ouverts, les canaux sont créés, etc.
À long terme, si et seulement si une partie ou la totalité de la mise en mémoire tampon en question est effectuée au niveau IO en sortie, vous pouvez faire un sync
commande; mais cela est généralement peu probable dans un cas comme celui-ci.
À l'avenir, vous pourrez utiliser le -u
de Python possibilité d'exécuter le script. En général, de nombreuses commandes ont des options spécifiques à la commande pour désactiver la mise en mémoire tampon stdin/stdout, et vous pouvez également avoir un certain succès générique avec le unbuffer
commande du expect
paquet.
Un Ctrl +C entraînerait le vidage des tampons au niveau du système lorsque le programme est interrompu à moins que la mise en mémoire tampon est effectuée par Python lui-même et il n'a pas implémenté la logique pour vider ses propres tampons avec Ctrl +C . Une suspension, un crash ou un kill ne serait pas si gentil.
Forcer stdin, stdout et stderr à être totalement sans tampon.