J'ai laissé un script en cours d'exécution sur une machine distante à partir du moment où 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 dans ps
.
$ ps aux | grep ipcheck
myuser 18386 0.0 0.0 18460 3476 pts/0 S+ Dec14 1:11 /bin/bash ./ipchecker.sh
Il est simplement sorti sur stdout sur une session locale (j'ai exécuté ./ipchecker.sh
forme une fenêtre de terminal local, pas de redirection, pas d'utilisation de screen
etc).
Existe-t-il de toute façon à partir d'une session SSH que je peux voir la sortie de cette commande en cours d'exécution (sans l'arrêter)?
Jusqu'à présent, le meilleur que j'ai trouvé est d'utiliser strace -p 18386
mais je reçois des hordes de texte qui montent sur l'écran, c'est beaucoup trop détaillé. Je peux arrêter strace
puis passer en revue la sortie et trouver le texte à imprimer sur stdout mais c'est très long et déroutant, et évidemment pendant qu'il est arrêté, je risque de manquer quelque chose. Je voudrais 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 redirection ou dans une session screen
etc, ce n'est pas un script critique pour la mission, donc je pourrais le faire. Au contraire, je vois cela comme un exercice d'apprentissage amusant.
Si tout ce que vous voulez faire, c'est espionner le processus existant, vous pouvez utiliser strace -p1234 -s9999 -e write
où 1234 est l'ID du processus. (-s9999
évite d'avoir des chaînes tronquées à 32 caractères et write
l'appel système qui produit la sortie.) Si vous souhaitez afficher uniquement les données écrites sur un descripteur de fichier particulier, vous pouvez utiliser quelque chose comme strace -p1234 -e trace= -e write=3
pour afficher uniquement les données écrites dans le descripteur de fichier 3 (-e trace=
empêche les appels système 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 pager tel que less
, ou l'envoyer vers un fichier avec strace -o trace.log …
.
Avec de nombreux programmes, vous pouvez détourner la sortie suivante avec un hack ptrace, soit vers votre terminal actuel, soit vers une nouvelle session d'écran. Voir Comment puis-je désavouer un processus en cours et l'associer à un nouveau shell d'écran? et autres threads liés.
Notez que selon la configuration de votre système, vous devrez peut-être exécuter toutes ces commandes strace
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 exécuter strace
en tant que root.) La plupart des distributions permettent uniquement à un processus de tracer ses enfants (ce fournit un avantage de sécurité modéré - il empêche certaines injections directes de logiciels malveillants, mais n'empêche pas l'injection indirecte en modifiant les fichiers). Ceci est contrôlé par le kernel.yama.ptrace_scome
sysctl.
Vous pouvez accéder à la sortie via le système de fichiers proc
.
tail -f /proc/<pid>/fd/1
1
= stdout, 2
= stderr
Dans BSD, vous pouvez utiliser watch
qui espionne un tty donné, par exemple.
watch /dev/pts/0
Sous Linux, ce ne sera pas possible si le processus n'a pas été exécuté sous multiplexeur auparavant comme screen
ou tmux
. Voir aussi: Reptyr: attacher un processus en cours d'exécution à un nouveau terminal
Il semble que le seul moyen soit de déboguer le processus (par exemple strace
, dtrace
/dtruss
, gdb
, lldb
, etc.).
Puisque vous avez utilisé strace
, pour récupérer une sortie significative, vous devez filtrer par une expression de qualification (telle que file
), puis analyser la sortie. Voici un exemple:
strace -e trace=write -s1000 -fp 18386 2>&1 | grep -o '".\+[^"]"'
Ce qu'il fait, il imprime l'opération d'écriture du processus (longueur 1000) spécifié par PID (utilisez pgrep
pour le trouver par son nom), redirige l'erreur standard vers la sortie (à filtrer) et imprime une chaîne entre guillemets.
Si vous avez affaire à 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érifier help read
pour plus de paramètres (par exemple -n
pour imprimer après un certain nombre de caractères, plutôt que la 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? at stackoverflow
Je vous conseille de créer un canal nommé (mkfifo
), puis d'écrire dans ce fichier. Ensuite, lisez-le. Vous pouvez toujours le faire avec des choses comme tail
, pour minimiser la sortie, etc. Chaque fois que vous effacez le canal (lu à partir de celui-ci), il est effacé, donc la sortie n'est pas conservée.
L'autre option serait de tout écrire dans un fichier (un peu comme un fichier journal) puis de l'analyser à tout moment. Ce serait l'action préférée, si vous souhaitez conserver toutes les sorties.
Vous pourrez peut-être jeter un œil à l'écran distant à l'aide de ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scale
où localhost
doit être remplacé par vos identifiants de connexion au serveur distant et :0.0
avec le numéro d'affichage de votre interface graphique.
Utilisation x11vnc
, qui est un serveur VNC pour votre session X à l'écran.
Lors de l'exécution sur l'une des 6 consoles virtuelles, essayez Sudo setterm -dump 2 -file /dev/stdout
, où vous remplacez 2
avec le vc approprié.
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 terminal avec:
tail -f Nohup.out
Cela fonctionne bien pour moi.
Analyse de la sortie de strace:
J'ai utilisé le réponse du 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, c'est probablement un descripteur de fichier et peut être différent pour votre processus.) Ensuite, j'ai écrit un rapide script Ruby pour les analyser et les afficher.
Collez 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'oubliez pas chmod a+x /usr/bin/parse_strace.rb
J'invoque strace -xx
(sort hex, donc le regex correspond correctement), tuyauterie (y compris STDERR) à mon script avec 9
comme premier argument.
Sudo sh -c 'strace -xx -p28223 -s9999 -e write 2>&1 | parse_strace.rb 9'
Et, le tour est joué, il sort le STDOUT original, les nouvelles lignes, la couleur et tout!
Une méthode très simple pour obtenir la sortie serait de capturer votre sortie dans un fichier et de suivre ce fichier.
SI FAIRE: ./ipcheck
AU LIEU FAIRE: ./ipcheck> [remplacez par votre nom de fichier]
Cela créerait un fichier de sortie où se trouve votre script. Ensuite, à partir de tout autre shell bash, vous pouvez simplement suivre le fichier:
queue [remplacez par votre nom de fichier] -f
ne pouvez-vous pas obtenir l'ID de processus et communiquer avec lui avec USR1,
$pgrep -l '^ipchecker.sh$'
qui imprime le PID de votre script, puis utilisez-le pour
$ kill -USR1 PID
Je comprends que USR1 est un signal "défini par l'utilisateur", ce qui signifie que celui qui a créé le programme peut l'utiliser pour signifier "arrêter" ou "vider vos journaux" ou "imprimer foo mille fois" ou autre.