為什麼我不能 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,請說出來。
Make a
strace
oftail -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 處理程序說文件已更改(通常是附加的),那麼tail
1) 查找 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
命令,要麼進入其原始位置,而從不進入兩者。但不確定。