管道生產者如何告訴管道消費者它已經到達’文件結尾’?”(未命名管道,未命名管道)
我有一個應用程序需要生產者將文件名發送給消費者,並讓生產者在發送最後一個文件名並且到達文件末尾時向**消費者指示。
為簡單起見,在以下範例中,生產者
echo
使用和 進行展示printf
,而消費者使用 進行展示cat
。我試圖推斷“here file”方法但沒有成功,<<EOF
用於向生產者包裝器(如果存在這樣的東西)指示要查找的內容作為文件結束的指示。如果它有效,應該從輸出中cat
過濾。EOF
例 1)
輸入
{ echo "Hello World!" printf '\x04' echo "EOF" } <<EOF |\ cat
輸出
bash: warning: here-document at line 146 delimited by end-of-file (wanted `EOF') Hello World! EOF
例 2)
輸入
{ echo "Hello World!" printf '\x04' echo "EOF" } |\ cat <<EOF
輸出
bash: warning: here-document at line 153 delimited by end-of-file (wanted `EOF')
用於指示分隔符的“here files”方法僅適用於靜態文本而不適用於動態創建的文本是否正確?
– 實際應用 –
inotifywait -m --format '%w%f' /Dir | <consumer>
消費者正在等待將文件寫入目錄 /Dir。如果在寫入文件“/Dir/EOF”時,消費者只需通過編寫如下 shell 腳本來檢測邏輯文件結束條件,那就太好了:
inotifywait -m --format '%w%f' /Dir |<</Dir/EOF <consumer>
– 回應 Giles 的回答 –
理論上可以實現嗎
cat <<EOF hello world EOF
作為
SpecialSymbol="EOF" { echo hello echo world echo $SpecialSymbol } |\ while read Line; do if [[ $Line == $SpecialSymbol ]] break else echo $Line fi done |\ cat
理論上可能,我的意思是*“它會支持現有的使用模式並且只啟用以前非法語法的額外使用模式嗎?”* - 意味著不會破壞現有的法律法規。
對於管道,一旦所有生產者都關閉了對管道的文件描述符並且消費者已經讀取了所有數據,消費者就會看到文件的結尾。
所以,在:
{ echo foo echo bar } | cat
cat
一旦第二個echo
終止並cat
讀取了foo\n
和 ,就會看到文件結尾bar\n
。你沒有什麼可做的了。但是要記住的是,如果管道左側的某些命令啟動了某個後台程序,則該後台程序將繼承管道的 fd(其標準輸出),因此
cat
在該程序也死之前不會看到 eof或關閉其標準輸出。如:{ echo foo sleep 10 & echo bar } | cat
您會看到
cat
在 10 秒過去之前沒有返回。在這裡,您可能希望將
sleep
的標準輸出重定向到其他內容,例如/dev/null
如果您不希望將其(非)輸出饋送到cat
:{ echo foo sleep 10 > /dev/null & echo bar } | cat
如果您希望在執行左側子shell 中的最後一個命令之前關閉管道的寫入端
|
,您可以使用 關閉stdout 或重定向到子shell 中間的該子shellexec
,例如:{ echo foo exec > /dev/null sleep 10 } | (cat; echo "cat is now gone")
cat
但是請注意,除了命令之外,大多數 shell 仍將等待該子 shell 。因此,雖然您會cat is now gone
立即看到(foo
閱讀後),但您仍然需要等待 10 秒才能完成整個管道。當然,在上面的那個例子中,寫它會更有意義:echo foo | cat sleep 10
<<ANYTHING...content...ANYTHING
是一個here-document,它是使命令的stdin成為一個包含內容的文件。在那裡用處不大。\4
是一個字節,當從終端讀取時,將終端設備保存的數據刷新到從它讀取的應用程序(當沒有數據時,read()
返回 0,表示文件結束)。同樣,在這裡沒有任何用處。