为什么我不能`tail -f /proc/$pid/fd/1`?

为什么我不能`tail -f /proc/$pid/fd/1`?

我编写了一个简单的脚本,其中echo-es 其 PID:

#/bin/bash

while true; do
    echo $$;
    sleep 0.5;
done

我正在3844一个终端中运行所述脚本(它一遍又一遍地表示),并尝试tail在另一个终端中运行文件描述符:

$ tail -f /proc/3844/fd/1

它不会在屏幕上打印任何内容并挂起直到^c。为什么?

此外,所有 STD 文件描述符(IN/OUT/ERR)都链接到相同的点:

$ ls -l /proc/3844/fd/
total 0
lrwx------ 1 mg mg 64 sie 29 13:42 0 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 1 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 2 -> /dev/pts/14
lr-x------ 1 mg mg 64 sie 29 13:42 254 -> /home/user/test.sh
lrwx------ 1 mg mg 64 sie 29 13:42 255 -> /dev/pts/14

这是正常的吗?

运行 Ubuntu GNOME 14.04。

如果您认为这个问题属于 SO 或 SU 而不是 UL,请告诉我们。

答案1

做一个stracetail -f它解释了一切。有趣的部分:

13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 fstatfs(3, {...}) = 0
13791 inotify_init()                    = 4
13791 inotify_add_watch(4, "/path/to/file", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 read(4, 0xd981c0, 26)             = -1 EINTR (Interrupted system call)

它能做什么?它为该文件设置一个inotify处理程序,然后等待该文件发生某些情况。如果内核tail通过这个 inotify 处理程序表明文件已更改(通常是附加的),则tail1) 查找 2) 读取更改 3) 将它们写到屏幕上。

/proc/3844/fd/1您的系统上有一个符号链接/dev/pts/14,它是一个字符设备。不存在像“内存映射”这样可以通过它访问的东西。因此,没有任何内容的更改可以被签名到 inotify,因为没有可以访问的磁盘或内存区域。

该字符设备是一个虚拟终端,实际上就像网络套接字一样工作。在此虚拟终端上运行的程序正在连接到该设备(就像您通过 telnet 登录到 TCP 端口一样),并写入它们想要写入的内容。还有更复杂的事情,例如锁定屏幕、终端控制序列等,这些通常是通过ioctl()调用来处理的。

我想,你想以某种方式观看虚拟终端。它可以在linux上完成,但并不是那么简单,它需要一些类似网络代理的功能,以及这些调用的一些棘手的用法ioctl()。但有一些工具可以做到这一点。

目前我不记得哪个 debian 软件包有实现此目标的工具,但是通过一点谷歌搜索,您可能很容易找到它。

扩大:正如 @Jajesh 在这里提到的(如果你给了我,请给他+1),该工具被命名为watch.

扩展#2:@kelnos提到,一个简单的cat /dev/pts/14也足够了。我尝试过,是的,它有效,但不正确。我没有对此进行太多实验,但在我看来,进入该虚拟终端的输出似乎消失了任何一个cat命令,或到其原始位置,但绝不能同时到两者。但这并不确定。

答案2

中的文件/dev/pts不是常规文件,它们是虚拟终端的句柄。读取和写入的行为pts不是对称的(也就是说,写入的内容稍后可以从中读取,就像常规文件或 fifo/管道),而是由创建虚拟终端的进程调节:一些常见的行为是xterm 或 ssh 或agetty 或screen。控制进程通常会将按键分派给读取pts文件的进程,并在屏幕上呈现它们在pts.

因此,tail -f /dev/pts/14将打印您在启动脚本的终端上点击的键,如果您这样做,echo meh > /dev/pts/14消息meh将出现在终端中。

答案3

前段时间我发现了一个有点解决方法有时回答了检查输出到 STDOUT 的内容的必要性,假设您有一个pid过程并且您可以看到不友好的结果:

sudo strace -p $pid 2>&1 | grep write\(

答案4

我想,为此,您需要做的不是拖尾,而是观察输出。

$ watch -n2 ls -l /proc/3844/fd/

希望这是您所需要的。

相关内容