risposta-alla-domanda-sullo-sviluppo-web-bd.com

Come visualizzare l'output di un processo in esecuzione in un'altra sessione bash?

Ho lasciato uno script in esecuzione su una macchina remota da quando ci lavoravo localmente. Posso connettermi tramite SSH alla macchina come lo stesso utente e vedere lo script in esecuzione in ps.

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

È semplicemente in uscita su stdout in una sessione locale (ho eseguito ./ipchecker.sh forma una finestra terminale locale, nessun reindirizzamento, nessun uso di screen etc).

C'è comunque da una sessione SSH che posso visualizzare l'output di questo comando in esecuzione (senza fermarlo)?

Finora il migliore che ho trovato è usare strace -p 18386 ma vedo orde di testo che volano sullo schermo, è troppo dettagliato. Posso interrompere strace e quindi scorrere l'output e scoprire che il testo viene stampato su stdout ma è molto lungo e confuso, e ovviamente mentre è fermo potrei perdere qualcosa. Vorrei trovare un modo per vedere l'output dello script dal vivo come se stessi lavorando localmente.

Qualcuno può migliorare su questo? La risposta ovvia è riavviare lo script con il reindirizzamento o in una sessione screen ecc., Questo non è uno script mission-critical, quindi potrei farlo. Piuttosto, lo vedo come un divertente esercizio di apprendimento.

223
jwbensley

Se tutto ciò che vuoi fare è spiare il processo esistente, puoi utilizzare strace -p1234 -s9999 -e write dove 1234 è l'ID processo. (-s9999 evita che le stringhe vengano troncate a 32 caratteri e write la chiamata di sistema che produce output.) Se vuoi visualizzare solo i dati scritti su un particolare descrittore di file, puoi usare qualcosa come strace -p1234 -e trace= -e write=3 per vedere solo i dati scritti nel descrittore di file 3 (-e trace= impedisce la registrazione delle chiamate di sistema). Ciò non ti darà un output già prodotto.

Se l'output scorre troppo velocemente, puoi reindirizzarlo a un cercapersone come less o inviarlo a un file con strace -o trace.log ….

Con molti programmi, è possibile deviare l'output successivo con un hack ptrace, sul terminale corrente o su una nuova sessione dello schermo. Vedi Come posso rinnegare un processo in esecuzione e associarlo a una nuova shell dello schermo? e altri thread collegati.

Si noti che, a seconda della configurazione del sistema, potrebbe essere necessario eseguire tutti questi comandi strace come root anche se il processo è in esecuzione sotto l'utente senza privilegi aggiuntivi. (Se il processo è in esecuzione come un altro utente o è setuid o setgid, sarà necessario eseguire strace come root.) La maggior parte delle distribuzioni consente solo a un processo di tracciare i propri figli (questo offre un moderato vantaggio in termini di sicurezza: impedisce l'iniezione diretta di malware, ma non impedisce l'iniezione indiretta modificando i file). Questo è controllato da kernel.yama.ptrace_scome sysctl.

È possibile accedere all'output tramite il filesystem proc.

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

1 = stdout, 2 = stderr

164
tvlooy

In BSD, puoi usare watch che esegue il snoop di una data tty, ad es.

watch /dev/pts/0

In Linux, non sarà possibile se il processo non fosse stato eseguito in multiplexer prima come screen o tmux. Vedi anche: Reptyr: collega un processo in esecuzione a un nuovo terminale

Sembra che l'unico modo sia eseguire il debug del processo (ad esempio strace, dtrace/dtruss, gdb , lldb, ecc.).

Dato che hai usato strace, per recuperare qualsiasi output significativo, devi filtrare in base a un'espressione qualificante (come file), quindi analizzare l'output. Ecco un esempio:

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

Cosa stampa stampa l'operazione del processo (lunghezza 1000) specificato da PID (usa pgrep per trovarlo per nome), reindirizza l'errore standard nell'output (da filtrare) e stampa una stringa tra virgolette.

Se hai a che fare con l'output binario, puoi analizzare i caratteri delle sequenze di escape usando read (con -r) e printf (con %b), per esempio.

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

Dai un'occhiata help read per più parametri (ad esempio -n per stampare dopo un certo numero di caratteri, piuttosto che una nuova riga).

Ecco un esempio più 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

Per esempi che utilizzano qualsiasi processo, controllare: Come analizzare la stringa in Shell in testo normale? su stackoverflow

10
kenorb

Consiglio di creare una pipe con nome (mkfifo) e quindi scrivere su quel file. Quindi, leggi da esso. Puoi sempre farlo con cose come tail, per ridurre al minimo l'output, ecc. Ogni volta che cancelli la pipe (leggi da essa), viene cancellata, quindi l'output non viene conservato.

L'altra opzione sarebbe quella di scrivere tutto su un file (molto simile a un file di registro) e quindi analizzarlo in qualsiasi momento. Questa sarebbe l'azione preferita, se si desidera preservare tutto l'output.

4
polemon
  1. Potresti riuscire a sbirciare lo schermo remoto usando ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scale dove localhost deve essere sostituito dalle credenziali di accesso del server remoto e :0.0 con il numero visualizzato della tua GUI.

  2. Uso x11vnc, che è un server VNC per la tua sessione X sullo schermo.

  3. Durante l'esecuzione su una delle 6 console virtuali, prova Sudo setterm -dump 2 -file /dev/stdout, dove sostituisci 2 con il vc appropriato.

4
jippie

Puoi sempre avviare un processo con Nohup e &

Nohup rsync source_file dest_file &

Quindi, puoi controllare i progressi da qualsiasi tty con:

tail -f Nohup.out

Questo funziona bene per me.

3
Pablo Luna

Analisi dell'output di strace:

Ho usato risposta migliore (con il mio ID processo di 28223) ...

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

Per determinare che ci tengo a write(9. (Il 9 è usato di seguito, probabilmente è un handle di file e potrebbe essere diverso per il tuo processo.) Poi ho scritto un veloce Ruby per analizzarli e visualizzarli.

Incolla quanto segue in /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
}

Non dimenticare chmod a+x /usr/bin/parse_strace.rb

Invoco strace -xx (genera hex, quindi regex corrisponde correttamente), esegui il piping (incluso STDERR) nel mio script con 9 come il primo arg.

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

E, voilà, produce STDOUT originale del processo, nuove linee, colore e tutto!

Attaching to process STDOUT

3
Jeff Ward

Un modo molto semplice per ottenere l'output sarebbe catturare l'output in un file e adattarlo a quel file.

SE FARE: ./ipcheck

INSTEAD DO: ./ipcheck> [sostituisci il tuo nome file]

Ciò creerebbe un file di output in cui si trova lo script. Quindi da qualsiasi altra shell bash puoi semplicemente mettere in coda il file:

tail [sostituisci il tuo nome file] -f

1
MrAllen

non riesci a ottenere l'ID processo e comunicare con esso con USR1,

$pgrep -l '^ipchecker.sh$'

che stampa il PID del tuo script, quindi usalo per

$ kill -USR1 PID

Comprendo che USR1 è un segnale "definito dall'utente", il che significa che chiunque abbia creato il programma può usarlo per significare "chiudere" o "scaricare i registri" o "stampare pippo mille volte" o altro.

0
Saeed