Stdout

使用 here-strings 寫入 FD 時將 tee 輸出到 stdout

  • November 9, 2020

我正在嘗試在寫入自定義文件描述符時輸出 tee。例子:

exec 4>"/tmp/testfile.txt"; # open FD 4
tee -a >&4 <<< "Output this to stdout" # Write to open file
exec 4>&- # close FD

如果我改為執行,tee -a /proc/self/fd/4 <<< "Output this to stdout"我可以在終端/標準標準輸出中看到輸出。

我正在使用BASH 5.0.16(1)-release。

我嘗試在 FD 1(stdout)和 FD 4 之間建立連接,但是我的字元串不會被寫入文件。

非常感謝!

編輯: 請參考@Stéphane Chazelas 的回答。我下面的更新可能是正確的,但方法很複雜。

更新: 我猜我越來越近了。嘗試時tee <<< "Output this to stdout" >(tee -a >&4),我實際上可以在終端中看到輸出並將其寫入文件,但由於某種原因,它會覆蓋內容並且似乎沒有附加(-a)。

更新 2: 我覺得我現在發現了我的錯誤。

**第一:**使用 Bash Process Substitution 我能夠通過兩次使用 tee 輸出到 stdout 並寫入我的 FD。我是這樣做的:

exec 4>"/tmp/testfile.txt"; # open FD 4
tee >(tee -a >&4) <<< "Output this to stdout" # Write to open file
exec 4>&- # close FD

如前所述,文件內容被覆蓋,這是答案的第二部分。

**第二:**我完全忘記了尋找職位!如果我使用exec 4&gt;"..."查找位置(或指針)打開文件,則位於文件的開頭。在這種情況下,追加就像覆蓋文件。為了解決這個問題,文件描述符需要在任何將目前位置設置為文件末尾的操作之前讀取完整的文件。一種解決方案就是使用cat. 當然我還需要打開文件進行閱讀(<>)。

最後: 這對我有用。它打開一個文件的 FD,讀取它的內容並附加到它。

exec 4&lt;&gt;"/tmp/testfile.txt"; # open FD 4 read (&lt;) and write (&gt;)
cat &lt;&4 &gt;/dev/null; tee &gt;(tee -a &gt;&4) &lt;&lt;&lt; "Output this to stdout" # read fd (&gt;/dev/null to silent the output) for correct position and append to. Also output to stdout
exec 4&gt;&- # close FD (this closes it completly, so no need for exec 4&lt;&-)

請記住: 如果您使用多個修改文件的程序,這實際上可能要小心。如果我沒看錯,那不是“真正的”追加。範例:您做了一隻貓,位置是 3。同時其他人在文件中追加了兩行。如果您現在使用目前已知位置追加,則其他兩行將失去。


我想我又學到了一點關於 Unix 系統中文件讀取的知識。總的來說,我可能需要過度考慮開設 FD 的想法。如果您知道該文件將是空的,那您就可以了。但是對於已經有內容和 esp 的文件可能會有風險。當您的指針不是最新的時,另一個程序可能會寫入它。我可能會錯誤地解釋某些技術方面的問題,但在某些方面應該是正確的。

If you want to write the same input to both fd 1 and 4, you'd use zsh` and do something like:

cat &lt;&lt;&lt; some-input &gt;&1 &gt;&4

(or just &lt;&lt;&lt; some-input &gt;&1 &gt;&4 as cat happens to be the default $NULLCMD)

In zsh, and if the multios option is enabled (as it is by default), redirecting a fd (here 1 as &gt; is short for 1&gt;) several times for output causes that fd to be redirected to an internal teeing process that multiplexes the output to all the targets.

While &lt;&lt;&lt; (also a zsh extension) is now supported by quite a few other shells (including bash), that multios feature is not.

On systems other than Linux and Cygwin, you could also do:

tee /dev/fd/4 &lt;&lt;&lt; some-input

As on most systems (except those 2 mentioned above), opening /dev/fd/4 does the same as duplicating fd 4 (same as {fd}&gt;&4).

On Linux and Cygwin however, that’s not what happens. Instead, opening /dev/fd/4 (same as /proc/self/fd/4 there) works as if you were opening the file currently open on that fd anew from scratch.

So, if fd 4 points to a socket for instance, that won’t work as you can’t open() a socket, and if it’s a regular file, opening it with &gt; will cause the file to be truncated.

With tee -a /dev/fd/4 &lt;&lt;&lt; some-input, you can avoid the truncation, but beware fd 4 will be left asis, so if you write data again to fd 4, it will likely overwrite what was output by tee. You’d need the fd 4 to have also been opened in append mode (which guarantees all writes are done at the end) to avoid it.

Doing:

tee &gt;(cat &gt;&4) &lt;&lt;&lt; some-input

Also addresses the problem, but means shoving the data through an extra cat process.`

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