it-swarm.cn

如何在另一个bash会话中查看正在运行的进程的输出?

从本地工作开始,我就已经在远程计算机上运行了一个脚本。我可以以同一用户的身份通过SSH连接到计算机,并查看ps中运行的脚本。

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

它只是在本地会话上输出到stdout(我运行./ipchecker.sh形成本地终端窗口,不重定向,不使用screen等)。

无论如何,SSH会话中是否可以查看此正在运行的命令的输出(而无需停止它)?

到目前为止,我发现最好的方法是使用strace -p 18386,但我看到成群的文字在屏幕上飞舞,其内容过于详尽。我可以停止strace,然后在输出中进行筛选,并找到将文本打印到stdout的方法,但是它很长且令人困惑,显然在停止时我可能会错过一些东西。我想找到一种方法来实时查看脚本输出,就像在本地工作一样。

任何人都可以对此进行改进吗?显而易见的答案是通过重定向或在screen会话等中重新启动脚本,这不是关键任务脚本,因此我可以这样做。相反,我认为这是一个有趣的学习练习。

223
jwbensley

如果您只想监视现有进程,则可以使用strace -p1234 -s9999 -e write,其中1234是进程ID。 (-s9999避免将字符串截断为32个字符,而write避免产生输出的系统调用。)如果只想查看写在特定文件描述符上的数据,则可以使用strace -p1234 -e trace= -e write=3仅查看写入文件描述符3的数据(-e trace=防止记录系统调用)。那不会给您已经产生的输出。

如果输出滚动太快,则可以将其通过管道传送到less之类的寻呼机中,或将其发送到带有strace -o trace.log …的文件中。

使用许多程序,您可以通过ptrace hack将后续输出转移到当前终端或新的屏幕会话。请参阅 如何放弃正在运行的进程并将其关联到新的屏幕外壳? 和其他链接的线程。

请注意,根据系统的设置方式,即使该进程在没有额外特权的情况下在您的用户下运行,也可能需要以root用户身份运行所有这些strace命令。 (如果该进程以其他用户身份运行,或者是setuid或setgid,则需要以root用户身份运行strace。) 大多数发行版仅允许进程跟踪其子级 (此操作提供了适度的安全性好处-阻止了一些直接的恶意软件注入,但没有通过修改文件阻止间接的注入)。这由kernel.yama.ptrace_scome sysctl控制。

198

您可以通过proc文件系统访问输出。

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

1 =标准输出,2 = stderr

164
tvlooy

在BSD中,您可以使用 watch 监听给定的tty,例如.

watch /dev/pts/0

在Linux中,如果进程未在screentmux之类的多路复用器之前运行,则不可能。另请参阅: Reptyr:将正在运行的进程附加到新终端

似乎唯一的方法是调试过程(例如stracedtrace/dtrussgdblldb等)。

由于您已使用strace来获取任何有意义的输出,因此需要按限定的表达式(例如file)进行过滤,然后解析输出。这是示例:

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

它执行的操作将打印由PID指定的进程(1000个长度)的写操作(使用pgrep通过名称查找它),将标准错误重定向到输出(进行过滤),并打印双引号字符串。

如果要处理二进制输出,则可以使用read(使用-r)和printf(带有%b),例如.

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

检查help read获取更多参数(例如-n在一定数量的字符(而不是换行符)之后打印)。

这是更完整的示例:

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

对于使用任何过程的示例,请检查: 如何在Shell中将strace解析为纯文本?

10
kenorb

我建议创建一个命名管道(mkfifo),然后写入该文件。然后,从中读取。您始终可以使用tail之类的方法来执行此操作,以最小化输出等。每当您清除管道(从管道读取)时,管道都会被清除,因此不会保留输出。

另一种选择是将所有内容写入文件(非常类似于日志文件),然后随时对其进行分析。如果要保留所有输出,这将是首选操作。

4
polemon
  1. 您也许可以使用ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scale窥视远程屏幕,其中localhost将被您的远程服务器登录凭据替换,而:0.0将被GUI的显示号所代替。

  2. 使用x11vnc,它是屏幕上X会话的VNC服务器。

  3. 在6个虚拟控制台之一上运行时,请尝试Sudo setterm -dump 2 -file /dev/stdout,在其中用适当的vc替换2

4
jippie

您总是可以使用Nohup启动进程

Nohup rsync source_file dest_file &

然后,您可以使用以下命令检查任何tty的进度:

tail -f Nohup.out

这对我来说很好。

3
Pablo Luna

解析strace的输出:

我用 最佳答案 (我的进程ID为28223)...

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

确定我在乎write(9。 (下面使用9,它可能是一个文件句柄,可能与您的过程有所不同。)然后,我编写了一个Ruby)快速脚本来解析和显示它们。

将以下内容粘贴到/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
}

别忘了chmod a+x /usr/bin/parse_strace.rb

我调用strace -xx(输出十六进制,因此正则表达式正确匹配),并以9作为第一个参数将管道(包括STDERR)管道到我的脚本中。

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

而且,瞧,它输出流程的原始STDOUT,换行符,颜色以及所有内容!

Attaching to process STDOUT

3
Jeff Ward

获得输出的一个非常简单的方法是将您的输出捕获到一个文件中并尾随该文件。

如果这样做:./ ipcheck

请勿执行:./ ipcheck> [用您的文件名替换]

这将在脚本所在的位置创建一个输出文件。然后,您可以从任何其他bash Shell中简单地尾文件:

尾部[replacewithyourfilename] -f

1
MrAllen

您无法获取进程ID并与USR1进行通信,

$pgrep -l '^ipchecker.sh$'

它会打印脚本的PID,然后使用它来

$ kill -USR1 PID

我了解到USR1是一个“用户定义”信号,这意味着创建该程序的任何人都可以使用它来表示“关闭”或“转储日志”或“打印foo千次”或其他方式。

0
Saeed