Rediriger stderr à partir d'un script déjà en cours d'exécution

14

J'exécute un script depuis plusieurs jours maintenant. J'ai redirigé stdout vers $HOME/mylog, mais je n'ai pas redirigé stderr car je pensais qu'il n'y aurait rien dessus. Soudain, des milliers de lignes ont commencé à sortir sur stderr, alors j'ai suspendu le travail. Existe-t-il un moyen de rediriger stderr vers $HOME/myerrmaintenant, sans avoir à redémarrer le script?

J'ai un accès sudo sur la box et c'est OS X.

Peut-être quelque chose utilisant le piégeage dtools?

Je ne peux pas perdre le travail que le script a fait jusqu'à présent et le redémarrer à partir de zéro. Existe-t-il un moyen de "vider les objets en mémoire" sur le disque, de geler le programme, de modifier les variables (par exemple les descripteurs de fichiers) et de reprendre avec le nouveau contexte?

Robottinosino
la source
doublon possible de la redirection / grep'ing du STDOUT d'un shell existant
Gilles 'SO- arrête d'être méchant'

Réponses:

12

Je pense que c'est possible si vous attachez le processus de l'interpréteur associé à gdb. Je l'ai essayé avec ce perl one-liner

 perl -e 'do { print "x\n"; sleep(1) } while(1)'

et cela fonctionne mais malheureusement pas avec un script bash similaire.


Tout d'abord, vous devez déterminer le PID de ce processus dont vous souhaitez capturer la sortie. Ensuite, démarrez gdbdans un autre terminal et exécutez les commandes gdb suivantes

attach PID
call close(2)
call open("/abs/olu/te/path/filename", 65, 384)
detach PID

après cela, toutes les données écrites stderrsont redirigées vers /abs/olu/te/path/filename, car

  • attach PID attache le processus à gdb et l'arrête
  • call close(2)ferme le stderrfiledescriptor du processus (car stdoutle filedescriptor est 1)
  • call open(...) ouvre un nouveau fichier et prend l'entier inutilisé le plus bas pour le descripteur de fichier nouvellement créé et
  • detach PID continue le processus

Au moins sur ma machine. Les deux premières lignes sont compatibles POSIX mais pas la troisième.

Le deuxième et le troisième argument de openla troisième ligne sont documentés dans man 2 open. Dans mon cas, 65 signifie que opendevrait créer le fichier et ouvrir le fichier en écriture seule, c'est-à-dire O_WRONLY | O_CREAT(défini dans fcntl.h). Le troisième argument indique à open de créer le fichier avec une autorisation de lecture et d'écriture pour l'utilisateur, c'est-à-dire S_IWUSR | S_IRUSR(défini dans sys/stat.h). Vous devrez peut-être trouver par vous-même les valeurs appropriées sur votre machine.

user1146332
la source
Cela a tellement bien fonctionné ... chapeau!
Robottinosino
8

C'est une réponse grossière et j'espère que quelqu'un d'autre fera mieux, mais si aucune autre idée n'apparaît, attachez gdb et forcez le processus à faire quelques appels système:

(gdb) attach 12345 # target PID
(gdb) p close(2)
(gdb) p open("errfile", O_WRONLY)
(gdb) c
Alan Curry
la source
Nifty. Je ne savais pas que gdb pouvait faire ça. Existe-t-il un moyen de le forcer à un numéro de descripteur de fichier spécifique? Comme dire si FD 1 n'est pas utilisé, et que le open()FD 1 s'empare? Ou vous n'avez qu'à appeler dup()quelques fois?
Patrick
fonctionne p open("errfile", O_WRONLY)vraiment sur votre machine?
user1146332
Vous pouvez coller un p dup2(xxx, 2)et ensuite p close(xxx)xxxest la valeur de retour du open. C'est une tâche délicate, mieux vaut ne pas utiliser ces commandes sur un processus de longue durée jusqu'à ce que vous soyez sûr qu'il n'y a pas d'autre choix.
Alan Curry
@ user1146332 il l'a fait quand je l'ai essayé parce que je l'ai utilisé /dev/nullcomme mon errfiledonc je n'en ai pas eu besoin O_CREAT. Et O_WRONLYétant une macro, qu'elle se développe ou non dépend de si gdb a arrêté le processus sur une ligne où les symboles de débogage sont disponibles et la macro est définie. L'injection de code dans un processus avec gdb est dangereuse et personne ne devrait simplement copier ces commandes sans les comprendre.
Alan Curry
@AlanCurry Je ne pense pas que gdb développe des macros si des informations générales de débogage sont disponibles. Vous devez compiler les sources avec des drapeaux spéciaux (voir ici ). De plus, il est très rare qu'un exécutable arbitraire sur votre système contienne des informations de débogage (laissez les informations être étendues avec des informations de macro). Mais je suis d'accord avec vous que l'injection de code n'est généralement pas recommandée, mais il peut y avoir des cas où vous en bénéficiez.
user1146332