¿Cómo ver el resultado de un proceso en ejecución en otra sesión bash?


200

He dejado una secuencia de comandos ejecutándose en una máquina remota desde que estaba trabajando localmente en ella. Puedo conectarme a través de SSH a la máquina como el mismo usuario y ver el script ejecutándose ps.

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

Simplemente está enviando a stdout en una sesión local (ejecuté ./ipchecker.shdesde una ventana de terminal local, sin redirección, sin uso de screenetc.).

¿Hay alguna forma de que desde una sesión SSH pueda ver el resultado de este comando en ejecución (sin detenerlo)?

Hasta ahora, lo mejor que he encontrado es usar, strace -p 18386pero recibo hordas de texto volando por la pantalla, es demasiado detallado. Puedo detenerme stracey luego examinar la salida y encontrar el texto impreso en stdout, pero es muy largo y confuso, y obviamente mientras está detenido podría perder algo. Me gustaría encontrar una manera de ver la salida del script en vivo como si estuviera trabajando localmente.

¿Alguien puede mejorar en esto? La respuesta obvia es reiniciar el script con redireccionamiento o en una screensesión, etc., este no es un script de misión crítica, por lo que podría hacer eso. Sin embargo, veo esto como un ejercicio de aprendizaje divertido.


¿Su proceso se ejecuta en una consola virtual o en un entorno similar a GUI / xterm?
jippie

44
Puede limitar la salida de strace a una syscall:strace -p 4232 -e write
otokan

@jippie La máquina está ejecutando una GUI completa (Linux Mynt 13, escritorio XFCE), encendí un terminal gnome.
jwbensley

3
Hay al menos una docena de preguntas similares en este sitio. Busque reptyr aquí para encontrar algunos de ellos (y una respuesta).
Stéphane Chazelas

Respuestas:


180

Si todo lo que quiere hacer es espiar el proceso existente, puede usar strace -p1234 -s9999 -e writedonde 1234 es la ID del proceso. ( -s9999evita tener cadenas truncadas a 32 caracteres y writela llamada al sistema que produce la salida). Si desea ver solo los datos escritos en un descriptor de archivo en particular, puede usar algo como strace -p1234 -e trace= -e write=3ver solo los datos escritos en el descriptor de archivo 3 ( -e trace=impide que el sistema llamadas de ser robado). Eso no le dará salida que ya ha sido producida.

Si el resultado se desplaza demasiado rápido, puede canalizarlo a un localizador como less, o enviarlo a un archivo con strace -o trace.log ….

Con muchos programas, puede desviar la salida posterior con un hack de ptrace, ya sea a su terminal actual o a una nueva sesión de pantalla. Consulte ¿Cómo puedo rechazar un proceso en ejecución y asociarlo a un nuevo shell de pantalla? y otros hilos vinculados.

Tenga en cuenta que dependiendo de cómo esté configurado su sistema, es posible que deba ejecutar todos estos stracecomandos como root, incluso si el proceso se ejecuta bajo su usuario sin privilegios adicionales. (Si el proceso se ejecuta como un usuario diferente o es setuid o setgid, deberá ejecutarse stracecomo root). La mayoría de las distribuciones solo permiten que un proceso rastree a sus hijos (esto proporciona un beneficio de seguridad moderado: evita la inyección directa de malware, pero no evita la inyección indirecta modificando archivos). Esto es controlado por el kernel.yama.ptrace_scomesysctl.


18
¿Supongo que no hay una forma de reducir la salida solo a la salida estándar ?
Jonás

3
¿Puedes explicar todos los argumentos?
Usuario

66
Había una gran cantidad de barras invertidas y números en gran parte de la salida que recibía de nodejs; ¿Alguna pista sobre en qué codificación podrían estar? También había mucho texto plano, que era todo lo que necesitaba.
ThorSummoner

3
"¿Puedes explicar todos los argumentos?" @Usuario:man strace
Pistos

3
@RafaelMoni Un programa para hacer lo que está pidiendo se llama depurador.
Gilles

140

Puede acceder a la salida a través del procsistema de archivos.

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

1= stdout, 2= stderr


77
Me da: 'no se puede abrir / proc / <my pid> / fd / 1 para leer: No existe tal dispositivo o dirección'.
Yaroslav Nikitenko

18
Sí <mi pid> debe ser el identificador de proceso
tvlooy

29
Esto no funcionará si la salida se dirige a un tty (o se redirige a /dev/null); solo funcionará si la salida se redirige a un archivo.
mattdm

1
Probado en Ubuntu 16.04 y no funciona. En una sesión hago: ping google.esy en otra como root: tail -f /proc/`pgrep ping`/fd/2y no se muestra nada.
david.perez

1
tienes razón. Porque fd 1 y 2 son enlaces simbólicos al dispositivo / dev / pts. No se puede seguir -fa pts dispositivo. Programe su comando ping como cronjob y luego haga lo mismo. tail -f entonces funcionará
tvlooy

9

En BSD, puede usar watchqué espías de un tty dado, por ejemplo

watch /dev/pts/0

En Linux, no será posible si el proceso no se ejecutó bajo multiplexor antes como screeno tmux. Ver también: Reptyr: Adjuntar un proceso en ejecución a una nueva terminal

Parece que la única manera de hacerlo es depurar el proceso (por ejemplo strace, dtrace/ dtruss, gdb, lldb, etc.).

Como ha utilizado strace, para obtener cualquier resultado significativo, debe filtrar por una expresión calificada (como file), luego analizar el resultado. Aquí hay un ejemplo:

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

Lo que hace imprime la operación de escritura del proceso (longitud 1000) especificada por PID (se usa pgreppara buscarlo por nombre), redirige el error estándar a la salida (para filtrar) e imprime una cadena entre comillas dobles.

Si se trata de una salida binaria, puede analizar caracteres de secuencias de escape utilizando read(con -r) y printf (con %b), p. Ej.

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

Verifique help readsi hay más parámetros (por ejemplo, -npara imprimir después de cierta cantidad de caracteres, en lugar de una nueva línea).

Aquí hay un ejemplo más completo:

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

Para ver ejemplos de cualquier proceso, consulte: ¿Cómo analizar strace en shell en texto plano? en stackoverflow


4
  1. Es posible que pueda echar un vistazo a la pantalla remota utilizando ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scaledónde localhostdebe ser reemplazado por las credenciales de inicio de sesión de su servidor remoto y :0.0con el número de pantalla de su GUI.

  2. Use x11vnc, que es un servidor VNC para su sesión X en pantalla.

  3. Cuando se ejecute en una de las 6 consolas virtuales sudo setterm -dump 2 -file /dev/stdout, intente reemplazarlas 2con la vc adecuada.


4

Aconsejaría hacer una tubería con nombre ( mkfifo) y luego escribir en ese archivo. Entonces, lea de ella. Siempre puede hacer eso con cosas como tail, para minimizar la salida, etc. Cada vez que limpia la tubería (leída de ella), se borra, por lo que la salida no se conserva.

La otra opción sería escribir todo en un archivo (como un archivo de registro) y luego analizarlo en cualquier momento. Esta sería la acción preferida, si desea conservar toda la salida.


3

Siempre puede iniciar un proceso con nohup y &

nohup rsync source_file dest_file &

Luego, podrá verificar el progreso desde cualquier tty con:

tail -f nohup.out

Esto me funciona bien.


66
Esta pregunta que me acerca de cómo ver la salida de un proceso en ejecución alerta, no cómo ejecutar un proceso en segundo plano como sugiere su respuesta
jwbensley

De hecho, su: ¡ninguna mención me ilumina! ¡Gracias!
Nam G VU

1

Una forma muy simple de obtener la salida sería capturar su salida en un archivo y seguir ese archivo.

SI LO HACE: ./ipcheck

INSTEAD DO: ./ipcheck> [replacewithyourfilename]

Esto crearía un archivo de salida donde se encuentra su script. Luego, desde cualquier otro shell bash, simplemente puede seguir el archivo:

cola [reemplazar con su nombre de archivo] -f


La redirección de archivos tiende a utilizar el almacenamiento en búfer basado en bloques de forma predeterminada (ver setbuf(3)), lo que puede ser tailproblemático.
thrig

55
Además, esto no ayuda con la pregunta, que se refería a cómo ver la salida de un proceso que ya se está ejecutando, no a cómo redirigir stdout para un nuevo proceso.
jwbensley

1

Analizando la salida de strace:

Usé la respuesta principal (con mi ID de proceso de 28223) ...

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

Para determinar que me importa write(9. (El 9 se usa a continuación, probablemente sea un identificador de archivo y puede ser diferente para su proceso). Luego escribí un script rápido de Ruby para analizarlo y mostrarlo.

Pegue lo siguiente en /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
}

No olvides chmod a+x /usr/bin/parse_strace.rb

Invoco strace -xx(genera hexadecimal, por lo que la expresión regular coincide correctamente), canalizando (incluido STDERR) a mi script con 9el primer argumento.

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

Y, ¡voila, genera el STDOUT original del proceso, las nuevas líneas, el color y todo!

Adjuntar al proceso STDOUT


0

¿No puede obtener la ID del proceso y comunicarse con USR1?

$pgrep -l '^ipchecker.sh$'

que imprime el PID de su script, luego lo usa para

$ kill -USR1 PID

Entiendo que USR1 es una señal "definida por el usuario", lo que significa que quien creó el programa puede usarlo para significar "apagar" o "volcar sus registros" o "imprimir miles de veces" o lo que sea.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.