簡體   English   中英

在 bash 中將空格分隔的計算值分配給數組與打印不一致

[英]Assigning space-separated computed values to array in bash is inconsistent with printing

我有以下純文本 az cli output :

echo $raw_containers_string
[
  {
    "name": "123"
  },
  {
    "name": "vbm-container"
  }
]

經過一些文本優化后,我返回了一個包含此(zsh)的字符串:

echo $raw_containers_string | grep name | cut -d ":" -f2 | tr '\n' " "
"123"  "vbm-container" %

(它最后還有一個 % 符號,但這是意料之中的)

我現在需要創建一個包含這 2 個字符串(123 和 vbm-container)的數組來遍歷它。

  1. declare -a arr=($(echo $raw_containers_string | grep name | cut -d ":" -f2 | tr '\n' " "))
    • 返回"123" "vb -co tir"
  2. arr=($(echo $raw_containers_string | grep name | cut -d ":" -f2 | tr '\n' " "))
    • 返回"123" "vb -co tir"

這些是數組的索引(如果重要的話):

➜  bash-az-list-blobs git:(master) ✗ echo $myvar[0]

➜  bash-az-list-blobs git:(master) ✗ echo $myvar[1]
 "123"  "vb
➜  bash-az-list-blobs git:(master) ✗ echo $myvar[2]
-co
➜  bash-az-list-blobs git:(master) ✗ echo $myvar[3]
t
➜  bash-az-list-blobs git:(master) ✗ echo $myvar[4]
i
➜  bash-az-list-blobs git:(master) ✗ echo $myvar[5]

➜  bash-az-list-blobs git:(master) ✗ echo $myvar[6]
r"

問題

  1. 我想了解為什么將其打印到終端和將其分配給變量之間的行為不同。
  2. 我還想知道如何將我的精煉分配給 zsh 中的一個數組,以便echo arr返回一個 2 元素可迭代數組。

您指望對未引用的變量/命令替換進行分詞來分隔數組的元素,並且顯然也更改了IFS 這些都是壞主意,它們加在一起是混亂的根源。 您還使用 zsh 進行交互式測試,它的分詞與 bash 非常不同,因此您會從中得到不同的奇怪結果。

首先,追蹤IFS的變化並修復它。 您似乎將其設置為非常奇怪的東西,至少包含“m”、“n”、“a”和“e”,因此它可能設置錯誤。

如果它確實需要更改,則需要防止它保持更改。 您可以通過使其成為命令的前綴(例如IFS=',' read field1 field2 )或在使用更改后的值(例如saveIFS="$IFS"; IFS=","; doSomethingWithIFS; IFS="$saveIFS"), or just find a different way to solve whatever you changed

其次,養成雙引號變量和命令替換的習慣。 在某些特定情況下您不應該對它們進行雙引號,而在某些情況下它是可選的,但最安全的做法是假設在大多數情況下應該雙引號。 shellcheck.net擅長指出引用問題(以及許多其他常見錯誤)。

不要在不帶引號的替換上使用分詞來填充數組,而是使用readarray -t將輸入的每一行讀入一個單獨的數組元素(或read -ra單詞讀入元素 - 但首先修復IFS ,或者它'也會奇怪地分裂)。 請注意,您不能將它們放在管道中,或者它們在子shell中執行並且值會丟失; 相反,使用進程替換: readarray -t < <(somecommand)

三、即grep | cut grep | cut的東西是 output 東西,在實際值周圍有額外的空格和引號。 無論如何,在解析 JSON 時,最好使用像jq這樣真正會說該語言的工具。

所以,所有這些都解決了,試試這個:

readarray -t arr < <(echo "$raw_containers_string" | jq -r '.[].name')

Léa Gris 指出,您可以通過使用--argjson而不是echo和 pipe 將字符串傳遞給jq來進一步簡化這一點:

readarray -t arr < <(jq -rn --argjson j "$raw_containers_string" '$j[].name')

(如果您需要檢查數組的內容——甚至是普通變量—— declare -p arrecho更可靠。)

使用jq

eval "names=($(echo "$raw_containers_string" |
               jq -r '.[].name|@sh'))"

現在您有一個 shell 數組names ,其中每個名稱都是一個元素。 管道到@sh意味着每個值都被引用為單獨的 shell 字,對eval是安全的。

暫無
暫無

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

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