
我想做的是在終端機視窗中運行 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 < p1
shell 會在呼叫 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 中的命令將退出。