web-dev-qa-db-fra.com

Comment un processus peut-il intercepter stdout et stderr d'un autre processus sous Linux?

J'ai des scripts qui auraient dû cesser de fonctionner mais qui traînent pour toujours. Existe-t-il un moyen de comprendre ce qu'ils écrivent sur STDOUT et STDERR de manière lisible?

J'ai essayé, par exemple, de faire:

$ tail -f /proc/(pid)/fd/1

mais ça ne marche pas vraiment. Ce fut un long coup de toute façon.

D'autres idées?

strace seul est assez verbeux et illisible pour voir cela.

Remarque: je suis seulement intéressé par leur sortie, pas par autre chose. Je suis capable de comprendre les autres choses par moi-même; cette question se concentre uniquement sur l'accès à stdout et stderr du processus en cours après le démarrer.

44

Je ne sais pas si cela fonctionnera pour vous, mais j'ai lu une page tout à l'heure décrivant une méthode qui utilise gdb

7
Jauco

Étant donné que je ne suis pas autorisé à modifier la réponse de Jauco, je donnerai la réponse complète qui a fonctionné pour moi (la page de Russell repose sur un comportement non garanti qui, si vous fermez le descripteur de fichier 1 pour STDOUT, la prochaine creat l'appel ouvrira FD 1.

Alors, lancez un simple script sans fin comme celui-ci:

import time

while True:
    print 'test'
    time.sleep(1)

Enregistrez-le dans test.py, exécutez avec

$ python test.py

Obtenez le PID:

$ ps auxw | grep test.py

Maintenant, attachez gdb:

$ gdb -p (pid)

et faites la magie de fd:

(gdb) call creat("/tmp/stdout", 0600)
$1 = 3
(gdb) call dup2(3, 1)
$2 = 1

Maintenant vous pouvez tail /tmp/stdout et voir la sortie utilisée pour aller à STDOUT.

43

Il y a plusieurs nouveaux utilitaires qui complètent la "méthode gdb" et ajoutent quelques touches supplémentaires. Celui que j'utilise maintenant s'appelle "reptyr" ("Re-PTY-er"). En plus de saisir STDERR/STDOUT, cela changera en fait le terminal de contrôle d'un processus (même s'il n'était pas précédemment attaché à un terminal).

La meilleure utilisation est de démarrer une session d'écran et de l'utiliser pour rattacher un processus en cours au terminal dans l'écran afin de pouvoir le détacher en toute sécurité et revenir plus tard.

Il est empaqueté sur des distributions populaires (Ex: 'apt-get install reptyr').

http://onethingwell.org/post/2924103615/reptyr

10
Mark Renouf

La méthode GDB semble meilleure, mais vous pouvez aussi le faire avec strace:

$ strace -p <PID> -e write=1 -s 1024 -o file

Via la page de manuel de strace:

   -e write=set
               Perform a full hexadecimal and ASCII dump of all the
               data written to file descriptors listed in the spec-
               ified  set.  For example, to see all output activity
               on file descriptors 3 and 5 use -e write=3,5.   Note
               that  this is independent from the normal tracing of
               the write(2) system call which is controlled by  the
               option -e trace=write.

Cela imprime un peu plus que ce dont vous avez besoin (la partie hexadécimale), mais vous pouvez sed cela facilement.

8
vherva

J'ai utilisé strace et décodé la sortie hexadécimale pour effacer le texte:

PID=some_process_id
Sudo strace -f -e trace=write -e verbose=none -e write=1,2 -q -p $PID -o "| grep '^ |' | cut -c11-60 | sed -e 's/ //g' | xxd -r -p"

J'ai combiné cette commande à partir d'autres réponses.

5
Lari Hotari

strace sort beaucoup moins avec seulement -ewrite (et non le =1 suffixe). Et c'est un peu plus simple que la méthode GDB, IMO.

Je l'ai utilisé pour voir la progression d'un travail d'encodage MythTV existant (Sudo car je ne possède pas le processus d'encodage):

$ ps -aef | grep -i handbrake
mythtv   25089 25085 99 16:01 ?        00:53:43 /usr/bin/HandBrakeCLI -i /var/lib/mythtv/recordings/1061_20111230122900.mpg -o /var/lib/mythtv/recordings/1061_20111230122900.mp4 -e x264 -b 1500 -E faac -B 256 -R 48 -w 720
jward    25293 20229  0 16:30 pts/1    00:00:00 grep --color=auto -i handbr

$ Sudo strace -ewrite -p 25089
Process 25089 attached - interrupt to quit
write(1, "\rEncoding: task 1 of 1, 70.75 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.76 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.77 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.78 % "..., 73) = 73^C
4
Jeff Ward

Vous pouvez utiliser rerirect ( https://github.com/jerome-pouiller/reredirect/ ).

Type

reredirect -m FILE PID

et les sorties (standard et erreur) seront écrites dans FILE.

reredirect README explique également comment restaurer l'état d'origine du processus, comment rediriger vers une autre commande ou rediriger uniquement stdout ou stderr.

3
Jérôme Pouiller

Vous ne dites pas votre système d'exploitation, mais je vais essayer de dire "Linux".

Voir ce qui est écrit sur stderr et stdout ne va probablement pas aider. Si cela est utile, vous pouvez utiliser tee (1) avant de démarrer le script pour prendre une copie de stderr et stdout.

Vous pouvez utiliser ps (1) pour rechercher wchan. Cela vous indique ce que le processus attend. Si vous regardez la sortie strace, vous pouvez ignorer la majeure partie de la sortie et identifier le dernier appel système (bloqué). S'il s'agit d'une opération sur un descripteur de fichier, vous pouvez revenir en arrière dans la sortie et identifier l'objet sous-jacent (fichier, socket, pipe, etc.). De là, la réponse est probablement claire.

Vous pouvez également envoyer au processus un signal qui le fait vider le core, puis utiliser le débogueur et le fichier core pour obtenir une trace de pile.

1
janm