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

jwb*_*ley 302 bash process io-redirection

当我在本地工作时,我已经在远程机器上运行了一个脚本。我可以以同一用户身份通过​​ SSH 连接到机器,并查看在ps.

$ ps aux | grep ipcheck
myuser  18386  0.0  0.0  18460  3476 pts/0    S+   Dec14   1:11 /bin/bash ./ipchecker.sh
Run Code Online (Sandbox Code Playgroud)

它只是在本地会话上输出到标准输出(我从./ipchecker.sh本地终端窗口运行,没有重定向,没有使用screen等)。

无论如何,我可以从 SSH 会话中查看此运行命令的输出(不停止它)吗?

到目前为止,我发现的最好的方法是使用,strace -p 18386但我在屏幕上看到成群的文本,它太详细了。我可以停下来strace,然后筛选输出,发现文本带打印到标准输出,但它非常长且令人困惑,很明显,当它停止时,我可能会错过一些东西。我想找到一种方法来实时查看脚本输出,就像我在本地工作一样。

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

Gil*_*il' 248

如果您只想监视现有进程,则可以使用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 将后续输出转移到当前终端或新屏幕会话。请参阅如何否认正在运行的进程并将其关联到新的屏幕外壳?和其他链接线程。

请注意,根据您系统的设置方式,您可能需要以straceroot身份运行所有这些命令,即使该进程在您的用户下运行而没有额外权限。(如果进程以不同的用户身份运行,或者是 setuid 或 setgid,则需要以straceroot身份运行。)大多数发行版只允许进程跟踪其子进程(这提供了适度的安全优势——它可以防止一些直接的恶意软件注入,但不会通过修改文件来防止间接注入)。这是由kernel.yama.ptrace_scomesysctl控制的。

  • 我不认为有办法将输出范围缩小到_只是标准输出_? (24认同)
  • 我从 nodejs 得到的很多输出中有很多反斜杠和数字;关于它们可能采用什么编码的任何线索?还有很多纯文本,这就是我所需要的。 (7认同)
  • @RafaelMoni 执行您要求的程序称为调试器。 (5认同)
  • “你能解释所有的论点吗?” @用户:`man strace` (4认同)
  • 你能解释所有的论点吗? (3认同)
  • @User https://explainshell.com/ 允许您粘贴命令,它会解释参数,例如 https://explainshell.com/explain?cmd=strace+-p1234+-s9999+-e+write (3认同)
  • @ThorSummoner 如果您在 strace 输出中看到反斜杠后跟双引号之间的三个八进制数字,则表示其数值由数字给出的字节。对于非 ASCII 字符,您会看到这一点。 (2认同)
  • 我来到这里寻找 STDout 并获得了宝贵的调试数据的宝库。谢谢! (2认同)
  • 我希望我不是在说一些愚蠢的话,但为了只获得标准输出,你可以使用: strace -p1234 -s9999 -e write 2>&1|grep '^write(1' (2认同)

tvl*_*ooy 242

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

tail -f /proc/<pid>/fd/1
Run Code Online (Sandbox Code Playgroud)

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

  • 如果输出要发送到 tty(或重定向到 `/dev/null`),这将不起作用——只有当输出被重定向到文件时,它才会起作用。 (45认同)
  • 是的 &lt;my pid&gt; 应该是 *你的进程 ID* (26认同)
  • 它给了我:“无法打开 /proc/&lt;my pid&gt;/fd/1 进行阅读:没有这样的设备或地址”。 (9认同)
  • `tail` 对我不起作用,我使用的是 `sudo cat /proc/&lt;pid&gt;/fd/1` (4认同)
  • 在 Ubuntu 16.04 上测试过,它不起作用。在一个会话中,我执行:`ping google.es` 并在另一个以 root 身份执行:`tail -f /proc/\`pgrep ping\`/fd/2` 并且没有显示任何内容。 (2认同)
  • 不知何故,“tail cat more”都不适合我,但“strace -ewrite”对我有用。我需要线程的 `stdout`,`strace -ewrite -p 50287` 显示它:`[pid 50287] write(1, "...", 97) = 97` - 它确实写入到 `1` 文件描述符。我在 gnome 终端上看到了输出,但实用程序没有得到它。 (2认同)

ken*_*orb 15

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

watch /dev/pts/0
Run Code Online (Sandbox Code Playgroud)

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

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

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

strace -e trace=write -s1000 -fp 18386 2>&1 | grep -o '".\+[^"]"'
Run Code Online (Sandbox Code Playgroud)

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

如果您正在处理二进制输出,则可以使用read(with -r) 和printf (with %b)来解析转义序列字符,例如

while read -r -t1 line; do printf "%b" $line; done
Run Code Online (Sandbox Code Playgroud)

检查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
Run Code Online (Sandbox Code Playgroud)

有关使用任何进程的示例,请检查:如何将 shell 中的 strace 解析为纯文本?在计算器溢出


小智 8

如果你想获得 stderr 和 stdout 你可以运行这个:

tail -f /proc/<pid>/fd/*
Run Code Online (Sandbox Code Playgroud)


Jef*_*ard 7

解析strace的输出:

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

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

确定我在乎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
}
Run Code Online (Sandbox Code Playgroud)

不要忘记 chmod a+x /usr/bin/parse_strace.rb

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

sudo sh -c 'strace -xx -p28223 -s9999 -e write 2>&1 | parse_strace.rb 9'
Run Code Online (Sandbox Code Playgroud)

而且,瞧,它输出进程的原始标准输出、换行符、颜色等等!

附加到进程 STDOUT


小智 6

您始终可以使用nohup&启动进程

nohup rsync source_file dest_file &
Run Code Online (Sandbox Code Playgroud)

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

tail -f nohup.out
Run Code Online (Sandbox Code Playgroud)

这对我来说效果很好。

  • 这个问题是关于如何查看警报运行进程的输出,而不是如何按照您的答案建议在后台运行进程 (9认同)
  • 事实上,你的 :nohup 提及启发了我!谢谢! (2认同)

pol*_*mon 4

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

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