Comment afficher la sortie d'un processus en cours dans une autre session bash?


200

J'ai laissé un script en cours d'exécution sur une machine distante depuis que j'y travaillais localement. Je peux me connecter via SSH à la machine en tant que même utilisateur et voir le script s'exécuter ps.

$ ps aux | grep ipcheck
myuser  18386  0.0  0.0  18460  3476 pts/0    S+   Dec14   1:11 /bin/bash ./ipchecker.sh

Il s'agit simplement de sortir sur stdout sur une session locale (je courais depuis ./ipchecker.shune fenêtre de terminal locale, pas de redirection, pas d'utilisation de screenetc.).

Y at-il quand même une session SSH que je peux voir le résultat de cette commande en cours d’exécution (sans l’arrêter)?

Jusqu'ici, le mieux que j'ai trouvé est d'utiliser, strace -p 18386mais je reçois des hordes de texte qui volent à l'écran, c'est beaucoup trop détaillé. Je peux m'arrêter straceet passer au crible le résultat et trouver le texte importé sur la sortie standard, mais il est très long et déroutant. Évidemment, tant qu'il sera arrêté, je risque de rater quelque chose. J'aimerais trouver un moyen de voir la sortie du script en direct comme si je travaillais localement.

Quelqu'un peut-il améliorer cela? La réponse évidente est de redémarrer le script avec la redirection ou dans une screensession, etc., ce n'est pas un script essentiel à la mission, donc je pourrais le faire. Plutôt, je vois cela comme un exercice d'apprentissage amusant.


Votre processus est-il exécuté dans une console virtuelle ou dans un environnement de type GUI / xterm?
Jippie

4
Vous pouvez limiter la sortie de strace à un appel système:strace -p 4232 -e write
otokan

@jippie La machine exécute une interface graphique complète (Linux Mynt 13, bureau XFCE), j'ai lancé un gnome-terminal.
Jwbensley

3
Il y a au moins une douzaine de questions similaires sur ce site. Cherchez reptyr ici pour en trouver quelques-uns (et une réponse).
Stéphane Chazelas

Réponses:


180

Si tout ce que vous voulez, c'est espionner le processus existant, vous pouvez utiliser strace -p1234 -s9999 -e write1234 comme ID de processus. ( -s9999évite que les chaînes ne soient tronquées à 32 caractères et que writel'appel système produise une sortie.) Si vous souhaitez afficher uniquement les données écrites sur un descripteur de fichier particulier, vous pouvez utiliser quelque chose de similaire strace -p1234 -e trace= -e write=3pour ne voir que les données écrites sur le descripteur de fichier 3 ( -e trace=empêche le système les appels d’être enregistrés). Cela ne vous donnera pas de sortie déjà produite.

Si la sortie défile trop rapidement, vous pouvez la diriger vers un pageur tel que less, ou l'envoyer dans un fichier avec strace -o trace.log ….

Avec de nombreux programmes, vous pouvez rediriger la sortie suivante avec un hack ptrace, vers votre terminal actuel ou vers une nouvelle session écran. Voir Comment puis-je désavouer un processus en cours et l'associer à un nouveau shell d'écran? et d'autres threads liés.

Notez que, selon la configuration de votre système, vous devrez peut-être exécuter toutes ces stracecommandes en tant que root, même si le processus s'exécute sous votre utilisateur, sans privilèges supplémentaires. (Si le processus s'exécute en tant qu'utilisateur différent ou est setuid ou setgid, vous devrez vous lancer en stracetant qu'utilisateur root.) La plupart des distributions n'autorisent qu'un processus à retracer ses enfants (cela offre un avantage modéré en matière de sécurité: cela empêche toute injection directe de malware, mais n'empêche pas l'injection indirecte en modifiant les fichiers). Ceci est contrôlé par le kernel.yama.ptrace_scomesysctl.


18
Je ne suppose pas qu'il y ait un moyen de réduire la sortie à la sortie standard seulement ?
Jonah

3
Pouvez-vous expliquer tous les arguments?
Utilisateur

6
Il y avait beaucoup de barres obliques inverses et de chiffres dans une grande partie de la sortie que j'obtenais de nodejs; Des pistes sur quel encodage ils pourraient être? Il y avait beaucoup de texte clair aussi, ce qui était tout ce dont j'avais besoin.
ThorSummoner

3
"Pouvez-vous expliquer tous les arguments?" @User:man strace
Pistos

3
@RafaelMoni Un programme pour faire ce que vous demandez est appelé un débogueur.
Gilles

140

Vous pouvez accéder à la sortie via le procsystème de fichiers.

tail -f /proc/<pid>/fd/1

1= stdout, 2= stderr


7
Cela me donne: "ne peut pas ouvrir / proc / <mon pid> / fd / 1 pour lire: aucun de ces périphériques ou adresses".
Yaroslav Nikitenko

18
ouais <mon pid> devrait être votre identifiant de processus
tvlooy

29
Cela ne fonctionnera pas si la sortie est dirigée vers un terminal (ou redirigé vers /dev/null) - cela ne fonctionnera que si la sortie est redirigée vers un fichier.
Mattdm

1
Testé sur Ubuntu 16.04 et cela ne fonctionne pas. Dans une session je fais: ping google.eset dans une autre en tant que root: tail -f /proc/`pgrep ping`/fd/2et rien n'est affiché.
david.perez

1
tu as raison. Parce que les fd 1 et 2 sont des liens symboliques vers le périphérique / dev / pts. Vous ne pouvez pas suivre un appareil pts -fa. Planifiez votre commande ping en tant que travail cron, puis procédez de même. tail -f fonctionnera ensuite
tvlooy,

9

Dans BSD, vous pouvez utiliser la watchrecherche d’un tty donné, par exemple

watch /dev/pts/0

Sous Linux, cela ne sera pas possible si le processus n'a pas été exécuté sous multiplexeur auparavant, tel que screenou tmux. Voir aussi: Reptyr: Attacher un processus en cours à un nouveau terminal

Il semble que le seul moyen est de déboguer le processus (par exemple strace, dtrace/ dtruss, gdb, lldb, etc.).

Puisque vous avez utilisé strace, pour extraire toute sortie significative, vous devez filtrer par une expression qualificative (telle que file), puis analyser la sortie. Voici un exemple:

strace -e trace=write -s1000 -fp 18386 2>&1 | grep -o '".\+[^"]"'

Cela permet d’imprimer l’opération d’écriture du processus (longueur de 1 000) spécifiée par PID (utilisée pgreppour le trouver par son nom), de rediriger l’erreur standard vers la sortie (à filtrer) et d’imprimer la chaîne entre guillemets.

Si vous utilisez une sortie binaire, vous pouvez analyser les caractères des séquences d'échappement en utilisant read(avec -r) et printf (avec %b), par exemple

while read -r -t1 line; do printf "%b" $line; done

Vérifiez help readdavantage de paramètres (par exemple, -npour imprimer après un certain nombre de caractères plutôt que de nouvelle ligne).

Voici un exemple plus complet:

strace -e trace=write -s1000 -fp 18386 2>&1 \
| grep --line-buffered -o '".\+[^"]"' \
| grep --line-buffered -o '[^"]\+[^"]' \
| while read -r line; do
  printf "%b" $line;
done

Pour des exemples utilisant n’importe quel processus, veuillez vérifier: Comment analyser strace dans shell en texte brut? à stackoverflow


4
  1. Vous pourrez peut-être jeter un coup d’œil à l’écran distant en utilisant ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scalelocalhostdoivent être remplacés vos identifiants de connexion au serveur distant et :0.0avec le numéro d’affichage de votre interface graphique.

  2. Utilisez x11vnc, qui est un serveur VNC pour votre session X à l'écran.

  3. Lors de l'exécution sur l'une des 6 consoles virtuelles, essayez de sudo setterm -dump 2 -file /dev/stdoutremplacer 2par le vc approprié.


4

Je conseillerais de créer un pipe nommé ( mkfifo) et d'écrire dans ce fichier. Ensuite, lisez-le. Vous pouvez toujours le faire avec des choses comme tail, minimiser la sortie, etc. Chaque fois que vous effacez le tuyau (lisez-le), il est effacé, de sorte que la sortie n'est pas préservée.

L’autre option serait d’écrire tout dans un fichier (un peu comme un fichier journal), puis de l’analyser à tout moment. Ce serait l'action recommandée si vous souhaitez conserver toutes les sorties.


3

Vous pouvez toujours lancer un processus avec nohup et &

nohup rsync source_file dest_file &

Ensuite, vous pourrez vérifier la progression de n'importe quel tty avec:

tail -f nohup.out

Cela fonctionne bien pour moi.


6
Cette question, je voudrais savoir comment afficher le résultat d'un processus en cours d'alerte, et non comment exécuter un processus en arrière-plan, comme le suggère votre réponse
jwbensley

En fait, votre mention: nohup m'éclaire! Merci!
Nam G VU

1

Un moyen très simple d'obtenir la sortie serait de capturer votre sortie dans un fichier et de l'ajuster à la fin.

SI FAIRE: ./ipcheck

AU LIEU DE FAIRE: ./ipcheck> [remplacez votre nom de fichier]

Cela créerait un fichier de sortie où se trouve votre script. Ensuite, depuis n'importe quel autre shell bash, vous pouvez simplement mettre le fichier en file d'attente:

queue [remplacezvotre nom de fichier] -f


La redirection de fichiers a tendance à utiliser la mise en mémoire tampon par défaut (voir setbuf(3)), ce qui peut poser tailproblème.
Thrig

5
De plus, cela n’aide en rien la question, qui concerne la visualisation de la sortie d’un processus en cours, et non la redirection de stdout pour un nouveau processus.
Jwbensley

1

Analyser la sortie de strace:

J'ai utilisé la réponse en haut (avec mon ID de processus de 28223) ...

> sudo strace -p28223 -s9999 -e write
...
write(9, "Info\nI\nCare\nabout", 55) = 55
...

Pour déterminer que je me soucie de write(9. (Le 9 est utilisé ci-dessous, il s'agit probablement d'un descripteur de fichier et peut être différent pour votre processus.) Ensuite, j'ai écrit un script Ruby rapide pour les analyser et les afficher.

Coller ce qui suit dans /usr/bin/parse_strace.rb

#!/usr/bin/ruby

num = ARGV[0]
STDIN.each { |line|
  if (line.match(/write\(#{ num },\s*"(.*?)"/)) then
    puts $1.split('\x').map { |s| s.to_i(16).chr }.join()
  end
}

N'oublie pas chmod a+x /usr/bin/parse_strace.rb

J'invoque strace -xx(sort hex, donc la regex correspond bien), en piping (y compris STDERR) à mon script avec 9comme premier argument.

sudo sh -c 'strace -xx -p28223 -s9999 -e write 2>&1 | parse_strace.rb 9'

Et voila, il sort le STDOUT original du processus, les nouvelles lignes, la couleur et tout!

Attachement pour traiter STDOUT


0

vous ne pouvez pas obtenir l'ID de processus et communiquer avec lui avec USR1,

$pgrep -l '^ipchecker.sh$'

qui imprime le PID de votre script, puis l’utilisez pour

$ kill -USR1 PID

Je comprends que USR1 est un signal "défini par l'utilisateur", ce qui signifie que quiconque a créé le programme peut l'utiliser pour signifier "arrêter" ou "vider vos journaux" ou "imprimer des milliers de fois" ou peu importe.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.