Linux

為什麼我不能 tail -f /proc/$pid/fd/1

  • October 11, 2018

我寫了一個簡單的腳本,它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,請說出來。

Make a straceof tail -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-ted 到一個 tcp 埠一樣),並寫入他們想要寫入的內容。還有一些更複雜的事情,例如鎖定螢幕、終端控制序列等,這些通常由ioctl()呼叫處理。

我認為,您想以某種方式觀看虛擬終端。它可以在 linux 上完成,但不是那麼簡單,它需要一些類似網路代理的功能,以及這些ioctl()呼叫的一些棘手用法。但是有一些工具可以做到這一點。

目前我不記得,哪個 debian 包有這個目標的工具,但是通過Google搜尋你可以很容易地找到它。

*擴展:*正如@Jajesh 在這裡提到的(如果你給我,給他+1),該工具被命名為watch.

擴展#2: @kelnos 提到,一個簡單cat /dev/pts/14的也足夠了。我試過了,是的,它有效,但不正確。我沒有對此進行大量實驗,但在我看來,進入該虛擬終端的輸出要麼進入cat命令,要麼進入其原始位置,而從不進入兩者。但不確定。

引用自:https://unix.stackexchange.com/questions/152773