bash 中的條件管道(自訂腳本)

bash 中的條件管道(自訂腳本)

我如何透過管道傳輸命令,並在腳本內部決定是否應該破壞管道。

它類似於這個問題。但awk我不想使用我自己的腳本:

check_ip | update_bind9

check_ip應該找到外部 IP ( curl -s ifconfig.co) 並將其與儲存在檔案 ( ~/.ip) 中的 IP 進行比較。

這是主要問題:

如果 IP 已更改,check_ip應透過管道傳遞 IP。如果不是,則應破壞管道。

這是否check_ip會破壞管道,或者update_bind9如果未使用 IP 進行調用,則會忽略該調用?

我做了一些測試,呼叫:check_ip | echo "ok"

我嘗試過了exit 0exit 1return truereturn false。試著set -e。沒有成功。

答案1

管道的所有組件同時開始– 無論第一個指令發生什麼,第二個指令總是會啟動。

所以這是需要處理空標準輸入的第二個指令。


但我想說,管道首先不是一個好的選擇。

(也許您將|(管道) 與||(布爾 OR) 混淆了?後者經常用作 if/then 的更短替代方案,例如,x || y僅當 x 失敗時才調用 y – 類似地,x && y僅當 x 成功時才調用 y。

一般來說,您應該使用 if/then 區塊。例如,如果check_ip當位址不同時傳回 0(成功),而當位址相同時傳回 1(失敗),則它看起來像這樣:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

或者,如果 update_bind9 可以自行確定位址(無需讀取 stdin),則將如下所示:

if check_ip_needs_updating; then
    update_bind9
fi

答案2

這個另一個答案很好。但是,如果您確實需要有條件地進行管道傳輸,那麼您可能會發現ifne有用:

ifne當且僅當標準輸入不為空時執行以下命令。

在你的情況下,它會像check_ip | ifne update_bind9

預設情況下,您的 Linux 中很可能ifne沒有安裝。在我的 Debian 10 中,它位於moreutils軟體包中。人們可能會認為額外的工具完全多餘,因為我們可以將 的輸出儲存check_ip在變數中並有條件地重複使用它,就像上面提到的答案一樣:

if addr=$(check_ip); then
    echo "$addr" | update_bind9
fi

條件可能是[ -n "$addr" ],無論如何;重要的是我們使用變數。像上面這樣的程式碼可能會解決您的問題,但通常至少有三個問題。假設command1 | command2而不是check_ip | update_bind9.此解決方案概括為:

if foo=$(command1); then
    echo "$foo" | command2
fi

進而:

  1. foo=$(command1)將從 的輸出中刪除所有尾隨換行符command1。然後echo "$foo"(或printf … "$foo") 將恰好添加一個換行符(或分別添加一些固定數量的換行符)。因此,command2可能無法獲得準確的輸出command1

  2. command1可能會產生包含 NUL 字元的輸出。 Bash 無法將 NUL 儲存在變數中(大多數 shell 不能;zsh 可以)。如果出現 NUL,command2則將無法獲得準確的輸出command1

  3. command1可能會產生巨大甚至無窮無盡的流,因此將其儲存在變數中可能是不可能的。

使用文件而不是變數可以解決除最後一個問題之外的所有問題。command1 | ifne command2對所有三個問題都免疫。

相關內容