[英]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)的數組來遍歷它。
declare -a arr=($(echo $raw_containers_string | grep name | cut -d ":" -f2 | tr '\n' " "))
"123" "vb -co tir"
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"
問題
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 arr
比echo
更可靠。)
使用jq
:
eval "names=($(echo "$raw_containers_string" |
jq -r '.[].name|@sh'))"
現在您有一個 shell 數組names
,其中每個名稱都是一個元素。 管道到@sh
意味着每個值都被引用為單獨的 shell 字,對eval
是安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.