Bash

從超時設置變數輸出

  • March 27, 2019

我正在嘗試通過 telnet 自動查詢狀態(在這種情況下,這不是我能夠解決的問題)。這個想法是對某些東西進行 grep 並將結果分配給一個變數,以便稍後傳遞給一個條件語句。複雜之處在於與目標設備的連結可能未啟動,因此如果未通過超時終止,腳本可能會無限期掛起。

這設置output為我所期望的,但不處理連結被關閉:

output=$(telnet 1.2.3.4 1234 | grep "something")

這將在處理連結斷開時吐出預期的輸出:

timeout --signal=9 3 telnet 1.2.3.4 1234 | grep "something"

我什至可以將輸出定向到文件,該文件將包含輸出:

timeout --signal=9 3 telnet 1.2.3.4 1234 | grep "something" > /tmp/tmpfile.txt

不幸的是,像這樣快速寫入/讀取文件不是一種選擇,因為它會填滿日誌文件。

但是,當我嘗試組合所有內容時,變數沒有設置:

output=$(timeout --signal=9 3 telnet 1.2.3.4 1234 | grep "something")

或者,更確切地說,它將它設置為一個空白值,因為如果我在執行上述之前設置它,那麼該變數之後是空白的。

telnet期望它的標準輸入上有一個 tty,但timeout把它拿走了。

如果你真的堅持使用 telnet,你可以通過添加--foreground選項來做到這一點timeout,如下所示:

output=$(timeout --foreground --signal=9 3 telnet 1.2.3.4 1234 2>&1 | grep "something")

此外,如果你可以nc在你的系統上安裝,你真的應該將它用於你的目的:

output=$(timeout 3 nc 1.2.3.4 1234 | grep "something")

如果兩者nc都不timeout --foreground是你的選擇,那麼你真的需要一個不需要 tty 的 telnet 替代方案。

我看到您標記了您的問題bash,因此您可以使用 Bash 自己的網路設施,因此您的線路可能會變成:

output=$(timeout 3 cat < /dev/tcp/1.2.3.4/1234 | grep "something")

如果甚至cat不是一個選項,那麼您可以用 Bash 中的單行腳本替換它,例如:

output=$(timeout 3 stdbuf -oL bash -c 'while read line ; do echo "${line}" ; done < /dev/tcp/1.2.3.4/1234 | grep "something"')

希望至少stdbuf(這是標準 coreutils 包的一部分)在您的系統中可用。

但是,在最後一種選擇中,請注意您的 grep 正則表達式:如果您有單引號,那麼您需要通過首先退出主單引號對來轉義它們。

如果您需要將變數(例如主機名和/或埠號)從您的 shell 傳遞到單行腳本,這也是必需的。例如:

hostname=1.2.3.4
portnumber=1234

output=$(timeout 3 stdbuf -oL bash -c 'while read line ; do echo "${line}" ; done < /dev/tcp/'"${hostname}"'/'"${portnumber}"' | grep "something"')

在這裡,我假設${hostname}${portnumber}值是可以信任的,即由您或其他不會給出非法、無效或危險值的可信來源提供。

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