
我如何透過管道傳輸命令,並在腳本內部決定是否應該破壞管道。
它類似於這個問題。但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 0
,exit 1
,return true
,return 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
進而:
foo=$(command1)
將從 的輸出中刪除所有尾隨換行符command1
。然後echo "$foo"
(或printf … "$foo"
) 將恰好添加一個換行符(或分別添加一些固定數量的換行符)。因此,command2
可能無法獲得準確的輸出command1
。command1
可能會產生包含 NUL 字元的輸出。 Bash 無法將 NUL 儲存在變數中(大多數 shell 不能;zsh 可以)。如果出現 NUL,command2
則將無法獲得準確的輸出command1
。command1
可能會產生巨大甚至無窮無盡的流,因此將其儲存在變數中可能是不可能的。
使用文件而不是變數可以解決除最後一個問題之外的所有問題。command1 | ifne command2
對所有三個問題都免疫。