這是在 Ubuntu 16.04 上,使用 bash 4.3.42 和 tcsh 6.19
如果打開 X 未使用的虛擬控制台並運行 bash,我會看到 stdin、stdout、stderr 和 tty 的專用檔案描述符(顯然)。
$ cd /dev/fd
$ ls
0 1 2 255
$ ls -al .
... .
... ..
... 0 -> /dev/tty3
... 1 -> /dev/tty3
... 2 -> /dev/tty3
... 255 -> /dev/tty3
如果我使用 tcsh,我會看到五個指向 tty 的非 std{in, out, err} 文件描述符,並且 std{in, out, err} 全部映射到/dev/null
.
% cd /dev/fd
% ls -al
... .
... ..
... 0 -> /dev/null
... 1 -> /dev/null
... 15 -> /dev/tty3
... 16 -> /dev/tty3
... 17 -> /dev/tty3
... 18 -> /dev/tty3
... 19 -> /dev/tty3
... 2 -> /dev/null
為什麼tcsh
需要這麼多文件描述符都指向 tty /dev/null
?這難道不是意味著在tcsh
分叉進程時需要稍微多一點的簿記工作,以便它們寫入控制台或從控制台讀取資料嗎?
答案1
tcsh
的組織方式與bash
(毫不奇怪)不同。兩者都很古老,對於細心的讀者來說充滿了有趣的怪癖。
tcsh
這種差異是由於管理文件描述符的方式造成的。與 不同的是bash
,它不為腳本編寫者提供操作編號文件描述符的方法。開發人員發現透過以下方式組織其文件描述符很方便移動標準流進入“保存”區域(真實腳本未使用),並且在運行命令時,它重複項那些命令(即子進程),以及關閉當命令完成時它們。
在原始碼中,sh.h
有這個塊這解釋了這些文件描述符的用法:
/*
* The shell moves std in/out/diag and the old std input away from units
* 0, 1, and 2 so that it is easy to set up these standards for invoked
* commands.
*/
#define FSAFE 5 /* We keep the first 5 descriptors untouched */
#define FSHTTY 15 /* /dev/tty when manip pgrps */
#define FSHIN 16 /* Preferred desc for shell input */
#define FSHOUT 17 /* ... shell output */
#define FSHDIAG 18 /* ... shell diagnostics */
#define FOLDSTD 19 /* ... old std input */
對於這兩個 shell,(至少對於 Linux)有多個指向同一個“真實”設備的鏈接/dev/fd
,因為這是偽終端驅動程式的組織方式。
tcsh
順便說一句,如果您從另一個 shell運行,您將得到不同的結果。但如果您的預設 shell 是tcsh
,您可能會看到問題中描述的那些檔案描述符。
答案2
這幾乎肯定是您的tcsh
配置中的某些內容(例如~/.login
,~/.cshrc
/etc/csh.*
) - 尋找重定向 stdin、stdout、stderr 的任何內容。
當我tcsh
在我的系統上運行時,我得到:
$ tcsh
> ls -lF /dev/fd/
total 0
lrwx------ 1 cas cas 64 Jun 26 13:28 0 -> /dev/pts/29
lrwx------ 1 cas cas 64 Jun 26 13:28 1 -> /dev/pts/29
lrwx------ 1 cas cas 64 Jun 26 13:28 2 -> /dev/pts/29
lr-x------ 1 cas cas 64 Jun 26 13:28 3 -> /proc/16570/fd/