OS X, bash: less 對打開的文件描述符起作用,cat 沒有
在我正在處理的 bash 腳本中(必須在 Ubuntu 和 OS X 上執行),我需要將數百個命令的輸出重定向到一個文件。
而不是附加
&>...
到所有這些,我只是做exec 9>&1 exec 5<>/tmp/some-file.txt exec 1>&5
到目前為止一切順利,但是在所有這些命令的中途,我需要讀取到目前為止已寫入的所有內容,同時保持文件描述符打開。
現在,在 Ubuntu 上我可以簡單地做
cat /dev/fd/5
或者
tee </dev/fd/5
但在 OS X 上,根本不會列印任何內容(並且命令會立即退出)。
但是,使用
less
我可以在兩者上看到文件的內容。我可以通過使用實現上述效果(在兩個作業系統上工作)
less /dev/fd/5 | tee
但這似乎是一個黑客行為。
那麼,為什麼
less
顯然可以看到cat
在 OS X 上看不到的東西呢?(或者所有 BSD 後代都受到影響?)還是我做錯了什麼?
在 OS X 上,就像在除 Linux 之外的所有系統上一樣,打開
/dev/fd/x
就像在做 adup(x)
,結果 fd 或多或少指向與 fd x 相同的打開文件描述,特別是在文件中具有相同的偏移量。Linux 在這裡是個例外。在 Linux 上,
/dev/fd/x
是指向 fd x 上打開的文件的符號連結,/proc/self/fd/x
並且/proc/self/fd/x
是指向文件的偽符號連結。在 Linux 上,當您執行 a 時,您將獲得與 open on 相同的文件的open("/dev/fd/x", somemode)
全新打開文件描述x
。您獲得的新 fd 與 fd x 沒有任何關係。特別是,偏移量將在文件的開頭(O_APPEND
當然,除非你用它打開它)並且模式(讀/寫/追加…)可能與 fd x 上的不同(你甚至可以得到與 fd x 上的完全不同的東西,比如在相反模式下打開管道的另一端)。(這也意味著這不適用於您無法*open()*的套接字)。所以,在 Linux 上,當你這樣做時
exec 5<> file echo test >&5
fd 5 的偏移量在文件末尾。如果你這樣做
cat <&5
你什麼也得不到。
當你這樣做時:
cat /dev/fd/5
您會看到
test
,因為獲得了一個與 fd 5 無關cat
的新只讀fd。file
在其他系統上,在
cat /dev/fd/5
cat
得到一個與 fd 5 重複的 fd,所以在文件末尾仍然有一個偏移量。它使用的原因
less
是由於某種原因,在該 fd 上執行 a 到文件的開頭(執行 aless
以確定文件是否可查找)。lseek()``lseek(1); lseek(0)
在這裡,如果您希望兩者都具有不同的偏移量,您可能希望有一個用於讀取的 fd 和一個用於寫入的 fd:
exec 5< file 9>&1 > file
或者,如果文件仍然存在,您將不得不重新打開該文件,或者按
lseek()
原樣less
執行。
ksh93
並且zsh
是唯一具有內置lseek()
運算符的外殼:cat <&5 <#((0)) # ksh93 {sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin
或者:
cat /dev/fd/5 5<#((0)) # ksh93 sysseek -u 5 0; cat /dev/fd/5 # zsh