Como visualizar a saída de um processo em execução em outra sessão do bash?

199

Eu deixei um script em execução em uma máquina remota desde quando eu estava trabalhando localmente. Posso conectar-me via SSH à máquina como o mesmo usuário e ver o script sendo executado ps.

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

É simplesmente a saída para stdout em uma sessão local (corri de ./ipchecker.shuma janela de terminal local, sem redirecionamento, sem uso de screenetc).

Existe alguma maneira de uma sessão SSH que eu possa ver a saída desse comando em execução (sem pará-lo)?

Até agora, o melhor que encontrei é o de usar, strace -p 18386mas recebo hordas de texto voando pela tela, é muito detalhado. Eu posso parar stracee peneirar a saída e encontrar o texto impresso em stdout, mas é muito longo e confuso e, obviamente, enquanto está parado, eu posso perder alguma coisa. Gostaria de encontrar uma maneira de ver a saída do script ao vivo como se estivesse trabalhando localmente.

Alguém pode melhorar isso? A resposta óbvia é reiniciar o script com redirecionamento ou em uma screensessão, etc., este não é um script de missão crítica, para que eu possa fazer isso. No entanto, vejo isso como um divertido exercício de aprendizado.

jwbensley
fonte
Seu processo está sendo executado em um console virtual ou em um ambiente semelhante à GUI / xterm?
jippie
4
Você pode limitar a saída do strace a um syscall:strace -p 4232 -e write
otokan
@jippie A máquina está executando uma GUI completa (Linux Mynt 13, desktop XFCE), iniciei um terminal gnome.
jwbensley
3
Há pelo menos uma dúzia de perguntas semelhantes neste site. Procure reptyr aqui para encontrar alguns deles (e uma resposta).
Stéphane Chazelas

Respostas:

180

Se tudo que você quer fazer é espionar o processo existente, você pode usar strace -p1234 -s9999 -e writeonde 1234 é o ID do processo. ( -s9999evita ter cadeias de caracteres truncadas em 32 caracteres e writea chamada do sistema que produz saída.) Se você deseja exibir apenas dados gravados em um descritor de arquivo específico, pode usar algo como strace -p1234 -e trace= -e write=3ver apenas os dados gravados no descritor de arquivo 3 ( -e trace=impede o sistema chamadas sejam registradas). Isso não fornecerá a saída que já foi produzida.

Se a saída estiver rolando muito rápido, você poderá direcioná-la para um pager como less, ou enviá-lo para um arquivo com strace -o trace.log ….

Em muitos programas, você pode desviar a saída subsequente com um ptrace hack, para o seu terminal atual ou para uma nova sessão de tela. Consulte Como posso negar um processo em execução e associá-lo a um novo shell de tela? e outros threads vinculados.

Observe que, dependendo de como seu sistema está configurado, pode ser necessário executar todos esses stracecomandos como root, mesmo que o processo esteja sendo executado no seu usuário sem privilégios adicionais. (Se o processo estiver sendo executado como um usuário diferente ou for setuid ou setgid, você precisará executar stracecomo root.) A maioria das distribuições permite apenas que um processo rastreie seus filhos (isso fornece um benefício moderado à segurança - evita a injeção direta de malware, mas não impede a injeção indireta modificando arquivos). Isso é controlado pelo kernel.yama.ptrace_scomesysctl.

Gilles
fonte
18
Suponho que não haja uma maneira de restringir a saída apenas à saída padrão ?
Jonah
3
Você pode explicar todos os argumentos?
Utilizador
6
Havia muitas barras invertidas e números em grande parte da saída que eu estava obtendo do nodejs; Alguma pista sobre em que codificação eles podem estar? Também havia bastante texto simples, o que era tudo o que eu precisava.
ThorSummoner
3
"Você pode explicar todos os argumentos?" @User:man strace
Pistos
3
@RafaelMoni Um programa para fazer o que você está pedindo é chamado de depurador.
Gilles
139

Você pode acessar a saída através do procsistema de arquivos.

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

1= stdout, 2= stderr

tvlooy
fonte
7
Isso me dá: 'não é possível abrir / proc / <meu pid> / fd / 1 para leitura: não existe esse dispositivo ou endereço'.
Yaroslav Nikitenko
18
sim <my pid> deve ser o seu ID do processo
tvlooy
29
Isso não funcionará se a saída estiver indo para um tty (ou redirecionada para /dev/null) - só funcionará se a saída for redirecionada para um arquivo.
mattdm
1
Testado no Ubuntu 16.04 e não funciona. Em uma sessão eu faço: ping google.ese em outra como root: tail -f /proc/`pgrep ping`/fd/2e nada é mostrado.
David.perez #
1
você está certo. Porque fd 1 e 2 são links simbólicos para o dispositivo / dev / pts. Você não pode seguir o dispositivo -fa pts. Agende seu comando ping como um cronjob e faça o mesmo. tail -f irá trabalhar
tvlooy
9

No BSD, você pode usar watchquais espiões um determinado tty, por exemplo,

watch /dev/pts/0

No Linux, não será possível se o processo não tiver sido executado no multiplexador antes, como screenou tmux. Consulte também: Reptyr: anexar um processo em execução a um novo terminal

Parece que a única maneira para depurar é o processo (por exemplo strace, dtrace/ dtruss, gdb, lldb, etc.).

Como você utilizou strace, para buscar qualquer saída significativa, é necessário filtrar por uma expressão qualificada (como file) e analisar a saída. Aqui está um exemplo:

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

O que ele faz: imprime a operação de gravação do processo (comprimento 1000) especificada pelo PID (use pgreppara encontrá-lo pelo nome), redireciona o erro padrão para a saída (a ser filtrada) e imprime uma string com aspas duplas.

Se você estiver lidando com saída binária, poderá analisar os caracteres das seqüências de escape usando read(com -r) e printf (com %b), por exemplo

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

Verifique se help readhá mais parâmetros (por exemplo, -npara imprimir após uma certa quantidade de caracteres, em vez de nova linha).

Aqui está um exemplo mais 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 exemplos usando qualquer processo, verifique: Como analisar strace no shell em texto sem formatação? no stackoverflow

kenorb
fonte
4
  1. Você pode espiar a tela remota usando ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scaleonde localhostdeve ser substituído pelas credenciais de login do servidor remoto e :0.0pelo número de exibição da sua GUI.

  2. Use x11vnc, que é um servidor VNC para a sua sessão X na tela.

  3. Ao executar em um dos 6 consoles virtuais sudo setterm -dump 2 -file /dev/stdout, tente substituí-lo 2pelo vc apropriado.

jippie
fonte
4

Eu aconselho a fazer um pipe nomeado ( mkfifo) e depois gravar nesse arquivo. Então, leia a partir dele. Você sempre pode fazer isso com coisas como tailminimizar a saída etc. Sempre que você limpa o tubo (leia a partir dele), ele é limpo, para que a saída não seja preservada.

A outra opção seria gravar tudo em um arquivo (como um arquivo de log) e analisá-lo a qualquer momento. Essa seria a ação preferida, se você quiser preservar toda a saída.

polemon
fonte
3

Você sempre pode iniciar um processo com nohup e &

nohup rsync source_file dest_file &

Em seguida, você pode verificar o progresso de qualquer tty com:

tail -f nohup.out

Isso funciona bem para mim.

Pablo Luna
fonte
6
Esta questão que eu sobre como exibir a saída de um processo em execução alerta, não como executar um processo em segundo plano como sua resposta sugere
jwbensley
De fato, sua menção: nohup me ilumine! Obrigado!
Nam G VU
1

Uma maneira muito simples de obter a saída seria capturar sua saída em um arquivo e segui-lo.

SE FAZER: ./ipcheck

EM VEZ DE: ./ipcheck> [replaceewithyourfilename]

Isso criaria um arquivo de saída onde seu script está localizado. Em qualquer outro shell bash, você pode simplesmente ajustar o arquivo:

tail [replaceewithyourfilename] -f

MrAllen
fonte
O redirecionamento de arquivo tende a usar o buffer baseado em bloco por padrão (consulte setbuf(3)), o que pode tornar um tailproblema.
thrig
5
Além disso, isso não ajuda na pergunta, que era sobre como visualizar a saída de um processo já em execução, não como redirecionar o stdout para um novo processo.
precisa saber é o seguinte
1

Analisando a saída do strace:

Usei a resposta principal (com meu ID de processo de 28223) ...

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

Para determinar que eu me importo write(9. (O 9 é usado abaixo, provavelmente é um identificador de arquivo e pode ser diferente para o seu processo.) Em seguida, escrevi um rápido script Ruby para analisá-los e exibi-los.

Cole o seguinte em /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ão esqueça chmod a+x /usr/bin/parse_strace.rb

Eu invoco strace -xx(gera hexadecimal, para que o regex corresponda corretamente), canalizando (incluindo STDERR) para o meu script com 9o primeiro argumento.

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

E, voilá, ele produz o STDOUT original do processo, novas linhas, cores e tudo!

Anexando ao processo STDOUT

Jeff Ward
fonte
0

você não pode obter o ID do processo e se comunicar com ele com USR1,

$pgrep -l '^ipchecker.sh$'

que imprime o PID do seu script e use-o para

$ kill -USR1 PID

Entendo que USR1 é um sinal "definido pelo usuário", o que significa que quem criou o programa pode usá-lo para "desligar" ou "despejar seus logs" ou "imprimir milhares de vezes" ou o que for.

Saeed
fonte