簡體   English   中英

一個bash命令,它使用另一個bash命令的輸出

[英]a bash command that uses the output of another bash command

我在谷歌雲有一組機器。 來自我的localhost:

gcloud compute instance-groups list-instances workers
OUTPUT:
NAME              ZONE           STATUS
workers-lya2    us-central1-a     RUNNING 
workers-23d4     us-central1-a     RUNNING 
...
workers-3asd3     us-central1-a     RUNNING    

我想從該列表中選擇一個隨機工作者名稱(比如workers-23d4 ),然后從第一個命令開始區域us-central1-m並將其粘貼到此命令中:

gcloud compute --project "my-project" ssh --zone "<zone_name_from_first_command> "<machine_name_from_first_command>"

bash上的一點點弱點。 請幫忙

以下命令從gcloud命令的輸出中選擇一個隨機行(不包括標題),然后將前兩個“單詞”存儲到machinezone變量中:

read -r machine zone unused <<< $(
  gcloud compute instance-groups list-instances workers | \
    perl -e '@_ = <>; shift @_; print $_[rand @_]'
)

在此命令之后,您可以使用machinezone變量,例如:

gcloud compute --project "my-project" ssh --zone "$zone" "$machine"

說明

perl命令使用菱形運算符<>讀取標准輸入到@_數組的所有行。 然后shift函數從@_刪除第一個項目。 rand @_返回0和@_中項目數之間的隨機十進制數。 十進制數在索引上下文中隱式轉換為整數。 因此,結果$_[rand @_]是一個隨機項@_ ,即,從gcloud指令的輸出的隨機線。

使用命令替換捕獲gcloudperl命令的輸出,並通過此字符串傳遞給read命令。

我在第一段中引用了單詞 ,因為shell根據IFS輸入字段分隔符 )變量將字符序列解釋為單詞。 因此,來自here字符串的IFS分隔的單詞被分配給machine (第一個單詞), zone (第二個單詞)和unused (其余行)變量。

-r選項禁用反斜杠的特殊含義。 換句話說,當給出此選項時, read將不會嘗試解釋輸入中的轉義序列。

大數線的案例

注意,解決方案意味着gcloud命令的輸出相對較小,即小到足以將整個文件粘貼到數組中。 此操作很快,但需要更多內存,而不是使用while <>循環逐行讀取。 如果輸出非常大,或者內存非常有限,這是另一種解決方案:

read -r machine zone unused <<< $(
  gcloud compute instance-groups list-instances workers | \
    perl -e '<>; $. = 0; rand($.) < 1 && ($line = $_) while <>; print $line'
)

其中<>讀取標題; $. 是保持當前行號的內置變量; 其余的都來自這本食譜

gcloud compute instance-groups list-instances workers | grep -v "^NAME"  | shuf -n 1 | awk '{print $1, $2}' | 
while read machine zone; do
    export SELECTED_MACHINE="$machine"
    export SELECTED_ZONE="$zone"
done
gcloud compute --project "my-project" ssh --zone "$SELECTED_ZONE" "$SELECTED_MACHINE"
  • grep -v "^NAME"剝離所有以NAME開頭的行(假設它只是你要剝離的第一行)
  • shuf從剩余的行中取一條隨機行
  • awk '{print $1, $2}'在空格處分割行並打印第一列和第二列
  • while read讀取awk的輸出到變量$machine$zone

更新 :上面的代碼適用於zsh,但不適用於bash,因為bash在子shell中運行管道(zsh不運行), export只傳遞變量到子進程,而不是父進程。 以下腳本通過在父進程中運行read來解決此問題:

machine_zone=$(gcloud compute instance-groups list-instances workers | 
              grep -v "^NAME"  | shuf -n 1 | awk '{print $1, $2}')
read machine zone <<< $machine_zone
gcloud compute --project "my-project" ssh --zone "$zone" "$machine"

如果從中提取隨機行的輸入很大,並且你想避免將其作為一個整體讀入內存,就像shuf那樣,請考慮Ruslan shuf的第二個perl解決方案。

否則, hansaplast的有用答案使用基於shuf的多實用程序方法,這種方法易於理解,但它可以簡化(並且,在撰寫本文時,有缺陷):

read -r machine zone _ < \ 
  <(gcloud compute instance-groups list-instances workers | tail +2 | shuf -n 1)

gcloud compute --project "my-project" ssh --zone "$zone" "$machine"
  • 通過read進程替換( <(...) )的read ,確保在當前 shell中執行read ,這意味着它創建的變量對其余命令可見,特別是第二次gcloud調用。

    • 相比之下,如果您使用管道( gcloud ... | read ... ),則read子shell中執行,並且后續命令將不會看到它創建的變量。
  • tail +2跳過輸入中的第一行(標題行)。

  • shuf -n 1從輸入中提取1個隨機選擇的行。

  • 注意_作為傳遞給read的第3個變量的名稱,它在前2個以空格分隔的標記被讀入$machine$zone之后接收輸入行的(未使用的) 其余部分

    • 如果我們只指定了machinezone$zone將不僅接收第二個令牌,而且還接收輸入行的其余部分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM