如何在 Bash 中取消設定數組範圍

如何在 Bash 中取消設定數組範圍

我正在嘗試刪除數組元素的範圍,但失敗了。

我的陣列

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

列印 0-1 數組看起來沒問題

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

現在我嘗試使用以下方法僅刪除這些元素:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

它刪除整個數組..

我做錯了什麼?

我找到了刪除數組範圍的其他方法,但為什麼上述方法不起作用?

for ((i=0; i<2; i++)); do unset a[$i]; done

編輯我也嘗試過但沒有運氣

unset -v 'a[@]::2'

答案1

要記住的一件事是,bash像 這樣的實作數組ksh,即作為關聯數組,其中鍵僅限於正整數(與其他語言相反,例如perlzsh例如)。

在:

a[123]=foo a[456]=bar a[789]=baz

在 bash 中,您有一個包含 3 個元素的關聯數組,而在 bash 中perl,您有一個包含 790 個元素的陣列(zsh 為 789 個元素)。

kshor中bash,傳回按鍵按數字排序的元素清單中的陣列${a[@]:0:1}的第一個元素,其中鍵大於或等於 0 。${a[123]}${a[0]}

unset 'a[123]'

(記住引用它,否則如果當前目錄中有一個名為 a1 或 a2 或 a3 的文件,它將失敗)是有道理的,因為它刪除了數組中的特定鍵。

unset 'a[@]::2'

但意義不大。bash只理解unset a,unset 'a[123]'unset 'a[*/@]',之後的任何內容都會被忽略,因此unset 'a[@]::2'unset 'a[@]please'執行相同的操作:取消設定整個數組。

如果要取消設定一系列鍵,則需要循環遍歷這些鍵:

若要取得數組的鍵列表,語法為"${!a[@]}"。不幸的是,應用範圍不適用於bashnor ksh,因此您需要一個臨時數組:

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

現在,如果您想像其他語言一樣考慮這些數組,那麼您不想使用unset.例如,如果數組一開始就不是稀疏的,並且您希望保持它的稀疏性(即將所有元素移動 2,而不是取消設定前兩個),您可以執行以下操作:

a=("${a[@]:2}")

也就是說,使用要保留的元素列表重新分配數組。

為了比較,與zsh.

a=({1..20})
unset 'a[12,16]'

unset 'a[16,20]'會將元素 12 到 16 設定為空值。

a=({1..20})
a[12,16]=()

(仍然是zsh)會將元素 17 到 20 移動 5 個位置,因此a[12]將包含17

答案2

  1. 如果你的陣列是連續/非稀疏(0..N-1 組中的所有元素)

    您可以使用以下命令刪除數組的第二個元素

    unset 'a[1]'
    

    若要刪除第二個、第三個和第四個元素,您可以使用例如

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done
    

    若要刪除除第一個和第二個元素之外的所有元素,您可以使用例如

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
    
  2. 通用解決方案(也適用於稀疏數組):您可以使用以下命令刪除數組的第二個元素

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"
    

    若要刪除第二個、第三個和第四個元素,您可以使用例如

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done
    

    若要刪除除第一個和第二個元素之外的所有元素,您可以使用例如

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done
    

相關內容