[英]Killing a specific process in a pipeline, from later in the pipeline
我正在編寫一個 shell 腳本,該腳本使用telnet
連接到服務器,發送查詢,然后獲取單行響應以進行進一步處理。 經典的解決方案是設置一個子shell,它echo
查詢,然后運行sleep
以保持連接打開足夠長的時間以返回響應:
#!/bin/sh
SERVER_ADD=localhost
SERVER_PORT=9995
result=$( ( echo '{"op":"get","path":"access"}'; sleep 30 ) | telnet "$SERVER_ADD" "$SERVER_PORT" )
echo "$result"
這是可行的,只是sleep
時間必須長於服務器響應所需的最長時間。 這意味着每次調用都需要很長時間,這將最小時間從幾十毫秒推到了幾十秒。 我需要我的腳本等待第一行響應,然后終止進程,以便它可以 go 繼續執行其他操作。
(是的:我知道顯而易見的答案是“使用expect
。”不幸的是,我的目標是嵌入式系統,添加expect
和編寫它的TcL
腳本引擎會使我的圖像大小增加大約一兆字節。不能.)
經過多次試驗和錯誤,我想出了以下內容:
#!/bin/sh
SERVER_ADD=localhost
SERVER_PORT=9995
result=$( ( echo '{"op":"get","path":"access"}'; sleep 30 ) |
telnet "$SERVER_ADD" "$SERVER_PORT" |
while read -r line; do
echo "$line"
killall sleep
done ) 2>/dev/null
echo "$result"
解釋
telnet
建立連接sleep
命令,這將結束子shell,從而結束 telnet 連接2>/dev/null
使用sleep
命令在終止時打印的“終止”消息這很好用,除了那個killall sleep
。 這將殺死該用戶控制下的每個sleep
實例。 大多數時候這不會是一個問題,但其他時候這將是一個嚴重混亂的錯誤來源。
我怎樣才能在需要時殺死sleep
(或整個子外殼),而不會造成附帶損害?
如果您有bash
您可以嘗試使用協同處理:
coproc telnet "$SERVER_ADD" "$SERVER_PORT"
echo '{"op":"get","path":"access"}' >&${COPROC[1]}
result=
while IFS= read -r line
do result+="$line
"
done <&${COPROC[0]}
coproc
bash 命令啟動一個進程,並創建一個名為COPROC
的數組,其中包含兩個文件描述符,即進程的標准輸入和標准輸出。 然后,您可以隨意書寫和閱讀它們。 如果您的 telnet 在一個命令后沒有結束,您可能需要發送第二個命令(例如echo 'exit' >&${COPROC[1]}
)來斷開連接。
您可以嘗試在運行 telnet 時用任意文件上的flock
命令替換睡眠。 然后第二個flock
代替睡眠將掛起。 第三個flock -u
可以隨時釋放鎖。
雖然典型的用法是flock lockfile command
,但這個腳本利用了flock filedescriptor
的用法。 這是因為flock -u
只能用於文件描述符,並且沒有命令(添加命令會強制將文件描述符arg 用作文件名)。
通過只打開一次鎖定文件,並為其分配文件描述符 5(任意), flock 5
將鎖定它, flock -u 5
將解鎖它。
result=$(
exec 5>mylock
flock 5
( echo '{"op":"get","path":"access"}'; flock mylock true ) |
telnet "$SERVER_ADD" "$SERVER_PORT" |
while read line; do
echo "$line"
flock -u 5
done
) 2>/dev/null
請參閱此其他問題以獲取對flock -u
的簡單測試。
您可以嘗試使用 fifo 將數據發送到 telnet,這樣您就可以在需要的時間關閉它。
rm -f myfifo
mkfifo myfifo
result=$(
telnet "$SERVER_ADD" "$SERVER_PORT" <myfifo |
( echo '{"op":"get","path":"access"}' >&5
while read -r line; do
echo "$line"
exec 5>&-
done
) 5>myfifo
)
語法5>myfifo
(無空格)打開一個新的 output 文件描述號 5 寫入 fifo。 echo >&5
寫入這個 fd。 exec 5>&-
關閉這個 fd。 這種語法應該在ash
中工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.