138 votes

Rediriger STDERR / STDOUT d'un processus APRÈS son démarrage, en utilisant la ligne de commande ?

Dans le shell, vous pouvez faire une redirection, > < etc., mais qu'en est-il APRÈS le lancement d'un programme ?

Voici comment j'en suis venu à poser cette question : un programme exécuté en arrière-plan de mon terminal n'arrête pas d'afficher un texte ennuyeux. Comme il s'agit d'un processus important, je dois ouvrir un autre shell pour éviter ce texte. J'aimerais pouvoir >/dev/null ou une autre redirection pour que je puisse continuer à travailler dans le même shell.

0 votes

Je sais que le moyen le plus simple de rediriger le STDOUT/STDERR est de DUP2 leurs descripteurs de fichiers AVANT de bifurquer. C'est une pratique assez standard, et probablement la façon dont les shells l'accomplissent en ce moment. Je ne suis pas sûr que cela donne une réponse, mais je pense que cela diminue les chances qu'il y en ait une bonne.

2 votes

1 votes

Vous pouvez utiliser reroutage

131voto

vladr Points 34562

Sans fermer et rouvrir votre tty (c'est-à-dire en vous déconnectant et en vous reconnectant, ce qui peut également mettre fin à certains de vos processus d'arrière-plan), il ne vous reste qu'un seul choix :

  • attachez-vous au processus en question en utilisant gdb, et exécutez :
    • p dup2(open("/dev/null", 0), 1)
    • p dup2(open("/dev/null", 0), 2)
    • détacher
    • quitter

Par exemple :

$ tail -f /var/log/lastlog &
[1] 5636

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/pts/0
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog

$ gdb -p 5636
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Attaching to process 5636
Reading symbols from /usr/bin/tail...(no debugging symbols found)...done.
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/librt.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
[New Thread 0x7f3c8f5a66e0 (LWP 5636)]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2

(no debugging symbols found)
0x00007f3c8eec7b50 in nanosleep () from /lib/libc.so.6

(gdb) p dup2(open("/dev/null",0),1)
[Switching to Thread 0x7f3c8f5a66e0 (LWP 5636)]
$1 = 1

(gdb) p dup2(open("/dev/null",0),2)
$2 = 2

(gdb) detach
Detaching from program: /usr/bin/tail, process 5636

(gdb) quit

$ ls -l /proc/5636/fd
total 0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/null
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog
lr-x------ 1 myuser myuser 64 Feb 27 07:36 4 -> /dev/null
lr-x------ 1 myuser myuser 64 Feb 27 07:36 5 -> /dev/null

Vous pouvez également considérer :

  • en utilisant screen ; l'écran fournit plusieurs ATS virtuels entre lesquels vous pouvez passer sans devoir ouvrir de nouvelles sessions SSH/telnet/etc.
  • en utilisant nohup ; cela vous permet de fermer et de rouvrir votre session sans perdre aucun processus d'arrière-plan dans le processus....

1 votes

Votre réponse à gdb n'a pas fonctionné avec tail -f file, et elle n'a pas fonctionné avec un programme de test en c compilé avec gcc -ggdb qui fait un printf toutes les secondes. De plus, cont rend impossible l'exécution d'autres commandes gdb, la commande serait detach, puis quit.

0 votes

Correct à propos du détachement, il est 2 heures du matin. :) Qu'est-ce qui n'a pas fonctionné exactement avec la solution gdb ?

0 votes

C'est ma faute, non seulement je n'avais pas le bon cont/détach, mais mon dup2 a été échangé. Ça devrait fonctionner maintenant.

60voto

naugtur Points 12383

Cela fera l'affaire :

strace -ewrite -p $PID

Ce n'est pas très propre (on voit des lignes comme : write(#,<text you want to see>) ), mais ça marche !


Vous pouvez également ne pas apprécier le fait que les arguments soient abrégés. Pour contrôler cela, utilisez l'option -s qui définit la longueur maximale des chaînes de caractères affichées.

Il attrape tous les flux, donc vous pourriez vouloir filtrer cela d'une manière ou d'une autre :

strace -ewrite -p $PID 2>&1 | grep "write(1" 

ne montre que les appels du descripteur 1. 2>&1 est de rediriger STDERR vers STDOUT, comme suit strace écrit dans STDERR par défaut.

6 votes

Ce n'est pas ce que le PO a demandé. Le PO a demandé à REDIRECTER loin de l'ATS, pas à intercepter. De plus, sur certaines plates-formes, Strace/truss insère des espaces entre les caractères du flux intercepté et/ou échappe les caractères non ASCII, et vous devrez également les traiter.

4 votes

Oui, cela fait la chose partiellement - mais pour certaines personnes lisant cette question, c'est tout ce dont ils ont besoin - pour voir ce qui se passe dans un programme exécuté par erreur pour écrire sur null ou sur une autre console. Je l'ai découvert après avoir trouvé cette question et je me suis dit que c'était une bonne idée (du moins pour moi). Et beaucoup de gens le trouvent utile, si mes yeux ne me trompent pas ;)

0 votes

Il est également possible que sudo est nécessaire.

21voto

jcomeau_ictx Points 15736

En reprenant les excellentes recherches de vladr (et d'autres) :

créer les deux fichiers suivants dans le même répertoire, quelque chose dans votre chemin, disons $HOME/bin :

silence.gdb, contenant (de la réponse de vladr) :

p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
detach
quit

et le silence, contenant :

#!/bin/sh
if [ "$0" -a "$1" ]; then
 gdb -p $1 -x $0.gdb
else
 echo Must specify PID of process to silence >&2
fi

chmod +x ~/bin/silence  # make the script executable

Maintenant, la prochaine fois que vous oublierez de rediriger firefox, par exemple, et que votre terminal commencera à être encombré de l'inévitable "(firefox-bin:5117) : Gdk-WARNING ** : XID collision, trouble ahead" :

ps  # look for process xulrunner-stub (in this case we saw the PID in the error above)
silence 5117  # run the script, using PID we found

Vous pouvez également rediriger la sortie de gdb vers /dev/null si vous ne voulez pas la voir.

3 votes

Mon gdb (v7.2) dispose d'une option pratique --batch-silent qui supprime la sortie et ne vous envoie pas dans la console gdb si quelque chose ne va pas (par exemple un processus manquant). BTW, $! fait référence au travail d'arrière-plan le plus récent, mais je ne pense pas qu'il puisse être utilisé dans le script lui-même. J'utilise un alias : alias silencebg='silence $!'

21voto

Mirek Points 41

Rediriger la sortie d'un processus en cours vers un autre terminal, un fichier ou un écran :

tty
ls -l /proc/20818/fd
gdb -p 20818

À l'intérieur de gdb :

p close(1)
p open("/dev/pts/4", 1)
p close(2)
p open("/tmp/myerrlog", 1)
q

Détacher un processus en cours d'exécution de bash terminal et le garder en vie :

[Ctrl+z]
bg %1 && disown %1
[Ctrl+d]

Explication :

20818 - juste un exemple de processus en cours d'exécution pid
p - affiche le résultat de la commande gdb
close(1) - ferme la sortie standard
/dev/pts/4 - terminal sur lequel écrire
close(2) - ferme la sortie d'erreur
/tmp/myerrlog - fichier dans lequel écrire
q - quitter gdb
bg %1 - exécuter le travail 1 arrêté en arrière-plan
disown %1 - détache le job 1 du terminal

2 votes

Cela ne fonctionnera pas si stdin (descripteur de fichier 0 ) est fermé.

1 votes

Cela a sauvé ma journée. J'avais un problème de fonctionnement dans une session ssl qui prenait une heure pour les premiers 10% et je ne voulais vraiment pas laisser mon ordinateur portable fonctionner pendant 10 heures de plus. Mais ai-je raison de supposer que votre redirection pour stderr devrait être la suivante p open("/tmp/myerrlog", 2) ?

0 votes

J'ai eu un problème très mineur avec l'exécution sur CentOS 6 - le fichier "/tmp/myerrlog" devait déjà exister. Il était trivial de le créer avec touch, bien sûr.

3voto

Roger Lipscombe Points 34344

Ce n'est pas une réponse directe à votre question, mais c'est une technique que j'ai trouvée utile ces derniers jours : Exécuter la commande initiale en utilisant 'screen', puis détacher.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X