從命名管道取得 stdin

從命名管道取得 stdin

我想做的是在終端機視窗中運行 python 並從命名管道重定向它的標準輸入。然後我寫入另一個終端機中的命名管道,並在 python 上執行該命令。

1號航廈:

mkfifo p1
python < p1

2 號航廈:

echo -n "print \"Hello World\"" > p1

發生的情況是 - python 列印Hello World並退出。我想做的是保持 python 運行以接受下一個命令。我如何在 shell 中執行此操作?

答案1

你需要

  • 即使它的標準輸入不是終端,也以互動方式運行 python:使用python -i
  • 保持管道的寫入端打開,否則python將偵測到EOF並退出。

所以:

python -i < p1

以及其他地方:

# open p1 on fd 3 of the shell process¹ for instance so stdout is
# left untouched in case you still want to write messages there.
exec 3> p1

# write something on fd 3. For instance with ksh/zsh's print
# builtin:
print -u3 '1j*1j'

# or for commands such as echo that can only print things
# on stdout (fd 1), duplicate that fd 3 to their fd 1:
echo '1j*1j' >&3 # short for 1>&3

# after echo (a builtin² in virtually all shells) returns, fd 1
# is restored to what it was before, but fd 3 remains open on
# the writing end of the pipe, so python still doesn't see EOF
# there.

echo normal message on stdout
echo 1+1 >&3 # more instructions for python
...
# and when done, close that file descriptor so python sees the EOF
# (assuming that fd 3 was the only file descriptor left open on
# the writing end of that pipe):
exec 3>&-

特別是在腳本中,作為替代方案,您可以重新導向整個命令群組,而不是使用exec³ 手動開啟和關閉 fd。

{
  echo ... >&3
  ...
  ...
} 3> p1

¹ fd 3 將由子程序繼承,並且(除了在 ksh93 中設定 close-on-exec 標誌)由這些進程中執行的其他命令(如果有)繼承。

² 當然,這也適用於非內建指令。對於非內建程序,shell 不需要保存和還原 fd 1,因為重定向僅在分叉來執行命令的子程序中執行。對於外部命令,除了自動執行此操作的 ksh93 之外,您實際上可能希望關閉 fd 3,這樣它就不會洩漏給它們,並且它們最終可能會產生後台進程 ( cmd >&3 3>&-)。

³ 請注意,在這種情況下,ksh93 不會在該 fd 3 上設定 close-on-exec 標誌。

答案2

您可以使用它在寫入tail -f後保持 fifo 開啟。echo

tail -n1 -f p1 | python

為什麼這有效

python正在閱讀來自p1.當到達文件末尾時,它將停止讀取。這是檔案讀取的正常行為,即使該檔案是命名管道。tail帶有-f(follow) 標誌的檔案將在到達文件末尾後繼續讀取。

答案3

您需要立即發送整個程式。

當您呼叫 run 時,python < p1shell 會在呼叫 python 之前等待輸入。也就是說,python 甚至沒有開始執行根本不直到整個資料流被 shell 讀取,然後將其全部傳遞給python.

即使改為運行python -u p1(即,無緩衝並從 file 讀取p1),python也會在執行任何文件之前嘗試讀取整個文件。

試試這個實驗。

1號航廈:

mkfifo p1
python < p1

2 號航廈:

cat > p1
print "Hello World"
print "Hello World"

您將看到您可以發送多行,但第 1 學期中的 python 不執行任何操作。現在按ctrl+ D。整個程序立即執行。

所以,總而言之,如果你想讓 python 從管道中讀取數據,你需要發送整個程式。你不能以這種方式互動地使用 python。

答案4

這是另一個解決方案。 1號航廈:

alec@MacBook-Air ~/hello $ rm -f my.fifo; mkfifo my.fifo 
alec@MacBook-Air ~/hello $ cat my.fifo 
command1
command2
...
alec@MacBook-Air ~/hello $ 

2 號航廈:

alec@MacBook-Air ~/hello $ cat > my.fifo 
command1
command2
...
alec@MacBook-Air ~/hello $ 

您在終端 2 中鍵入命令,然後觀察它們顯示在終端 1 中cat my.fifo | node ...。完成後,stdin使用 Ctrl-D 關閉終端 2。這將關閉my.fifo並且cat終端 1 中的命令將退出。

相關內容