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


199

从本地工作开始,我就已经在远程计算机上运行了一个脚本。我可以以同一用户的身份通过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会话等中重新启动脚本,这不是关键任务脚本,因此我可以这样做。相反,我认为这是一个有趣的学习练习。


您的进程是在虚拟控制台中还是在类似GUI / xterm的环境中运行?
jippie 2012年

4
您可以将strace的输出限制为一个系统调用:strace -p 4232 -e write
otokan 2012年

@jippie机器正在运行完整的GUI(Linux Mynt 13,XFCE桌面),我启动了gnome终端。
jwbensley

3
这个网站上至少有十二个类似的问题。在此处查找reptyr以找到其中的一些(和答案)。
斯特凡Chazelas

Answers:


180

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

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

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

请注意,取决于strace进程的设置方式,即使进程在您的用户下运行且没有额外特权,您也可能需要以root用户身份运行所有这些命令。(如果该进程以其他用户身份运行,或者是以setuid或setgid身份运行,则您将需要以straceroot用户身份运行。)大多数发行版仅允许进程跟踪其子进程(这具有中等安全性,它可以防止某些恶意软件直接注入,但不能通过修改文件来防止间接注入)。这由kernel.yama.ptrace_scomesysctl 控制。


18
我不认为有办法将输出范围缩小到标准输出范围吗?
约拿(Jonah)2013年

3
你能解释所有的论点吗?
用户

6
从nodejs获得的很多输出中都有很多反斜杠和数字。关于它们可能采用哪种编码的任何线索?也有很多纯文本,这是我所需要的。
ThorSummoner

3
“你能解释所有的论点吗?” @User:man strace
Pistos

3
@RafaelMoni一个执行您要求的程序的程序称为调试器。
吉尔斯2015年

139

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

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

1=标准输出,2=标准错误


7
它给我:“无法打开/ proc / <我的pid> / fd / 1进行读取:没有这样的设备或地址”。
Yaroslav Nikitenko '16

18
是的<my pid>应该是您的进程ID
tvlooy

29
如果输出将输出到tty(或重定向到/dev/null),则将不起作用-仅在将输出重定向到文件时才有效。
mattdm

1
在Ubuntu 16.04上测试过,它不起作用。在一个会话中,我执行以下操作:ping google.es在另一个会话中,我执行以下操作:作为root:tail -f /proc/`pgrep ping`/fd/2并且未显示任何内容。
david.perez

1
你是对的。因为fd 1和2是/ dev / pts设备的符号链接。您不能拖尾-fa pts设备。将ping命令安排为cronjob,然后执行相同的操作。tail -f将起作用
tvlooy

9

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

watch /dev/pts/0

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

看来唯一的办法是调试过程中(例如stracedtrace/ dtrussgdblldb,等)。

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

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

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

如果要处理二进制输出,则可以使用read(with -r)和printf (with %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解析为纯文本?在stackoverflow


4
  1. 您可能能够在使用远程屏幕偷看ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scale这里localhost是由远程服务器的登录凭据,来代替:0.0你的图形用户界面的显示数量。

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

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


4

我建议创建一个命名管道(mkfifo),然后写入该文件。然后,从中读取。您始终可以使用进行操作tail,以最大程度地减少输出等。每当您清除管道(从管道读取)时,管道都会被清除,因此不会保留输出。

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


3

您总是可以启动nohup

nohup rsync source_file dest_file &

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

tail -f nohup.out

这对我来说很好。


6
这个问题我想知道如何查看警报运行进程的输出,而不是如您的回答所建议的那样如何在后台运行进程
jwbensley

实际上,您的:nohup提法启发了我!谢谢!
Nam G VU

1

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

如果这样做:./ ipcheck

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

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

尾部[replacewithyourfilename] -f


默认情况下,文件重定向倾向于使用基于块的缓冲(请参阅参考资料setbuf(3)),这可能会引起tail问题。
thrig

5
同样,这也无济于事,该问题是关于如何查看已经运行的进程的输出,而不是如何为新进程重定向stdout。
jwbensley

1

解析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(输出十六进制,因此正则表达式正确匹配),将管道(包括STDERR)9作为第一个arg 传递到我的脚本中。

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

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

附加到过程STDOUT


0

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

$pgrep -l '^ipchecker.sh$'

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

$ kill -USR1 PID

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.