第二十四部分(陣列)

2020-08-13 06:07:25

2020-04-18
Bash 中的陣列僅限製爲單一維度。我們可以把它們看作是隻有一列的電子表格。

建立一個數組

陣列變數就像其它 bash 變數一樣命名,當被存取的時候,它們會被自動地建立。這裏是一個例子:

[me@linuxbox ~]$ a[1]=foo
[me@linuxbox ~]$ echo ${a[1]}
foo

這裏我們看到一個賦值並存取陣列元素的例子。通過第一個命令,把陣列 a 的元素 1 賦值爲「foo」。第二個命令顯示儲存在元素 1 中的值。在第二個命令中使用花括號是必需的,以便防止 shell 試圖對陣列元素名執行路徑名展開操作。

也可以用 declare 命令建立一個數組:

[me@linuxbox ~]$ declare -a a

使用 -a 選項,declare 命令的這個例子建立了陣列 a

陣列賦值

有兩種方式可以給陣列賦值。單個值賦值使用以下語法:

name[subscript]=value

這裏的 name 是陣列的名字,subscript 是一個大於或等於零的整數(或算術表達式)。注意陣列第一個元素的下標是 0,而不是 1。陣列元素的值可以是一個字串或整數。

多個值賦值使用下面 下麪的語法:

name=(value1 value2 ...)

這裏的 name 是陣列的名字,value… 是要按照順序賦給陣列的值,從元素 0 開始。

輸出整個陣列的內容

下標 *@ 可以被用來存取陣列中的每一個元素。與位置參數一樣,@ 表示法在兩者之中更有用處。

確定陣列元素個數

使用參數展開,我們能夠確定陣列元素的個數,與計算字串長度的方式幾乎相同。這裏是一個例子:

[me@linuxbox ~]$ a[100]=foo
[me@linuxbox ~]$ echo ${#a[@]} # number of array elements
1
[me@linuxbox ~]$ echo ${#a[100]} # length of element 100
3

我們建立了陣列 a,並把字串「foo」賦值給陣列元素 100。下一步,我們使用參數展開來檢查陣列的長度,使用 @ 表示法。最後,我們檢視了包含字串「foo」的陣列元素 100 的長度。有趣的是,儘管我們把字串賦值給陣列元素 100,bash 僅僅報告陣列中有一個元素。這不同於一些其它語言的行爲,這種行爲是陣列中未使用的元素(元素 0-99)會初始化爲空值,並把它們計入陣列長度。

找到陣列使用的下標

因爲 bash 允許賦值的陣列下標包含「間隔」,有時候確定哪個元素真正存在是很有用的。爲做到這一點,可以使用以下形式的參數展開:

${!array[*]}
${!array[@]}

這裏的 array 是一個數組變數的名字。和其它使用符號 *@ 的展開一樣,用引號引起來的 @ 格式是最有用的,因爲它能展開成分離的詞。

[me@linuxbox ~]$ foo=([2]=a [4]=b [6]=c)
[me@linuxbox ~]$ for i in "${foo[@]}"; do echo $i; done
a
b
c
[me@linuxbox ~]$ for i in "${!foo[@]}"; do echo $i; done
2
4
6

在陣列末尾新增元素

如果我們需要在陣列末尾附加數據,那麼知道陣列中元素的個數是沒用的,因爲通過 *@ 表示法返回的數值不能告訴我們使用的最大陣列索引。幸運地是,shell 爲我們提供了一種解決方案。通過使用 += 賦值運算子,我們能夠自動地把值附加到陣列末尾。這裏,我們把三個值賦給陣列 foo,然後附加另外三個。

[me@linuxbox~]$ foo=(a b c)
[me@linuxbox~]$ echo ${foo[@]}
a b c
[me@linuxbox~]$ foo+=(d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f

陣列排序

就像電子表格,經常有必要對一列數據進行排序。Shell 沒有這樣做的直接方法,但是通過一點兒程式碼,並不難實現。

#!/bin/bash
# array-sort : Sort an array
a=(f e d c b a)
echo "Original array: ${a[@]}"
a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort))
echo "Sorted array: ${a_sorted[@]}"

當執行之後,指令碼產生這樣的結果:

[me@linuxbox ~]$ array-sort
Original array: f e d c b a
Sorted array:
a b c d e f

指令碼執行成功,通過使用一個複雜的命令替換把原來的陣列(a)中的內容複製到第二個陣列(a_sorted)中。通過修改管道線的設計,這個基本技巧可以用來對陣列執行各種各樣的操作。

刪除陣列

刪除一個數組,使用 unset 命令:

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox ~]$ unset foo
[me@linuxbox ~]$ echo ${foo[@]}
[me@linuxbox ~]$

也可以使用 unset 命令刪除單個的陣列元素:

[me@linuxbox~]$ foo=(a b c d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox~]$ unset 'foo[2]'
[me@linuxbox~]$ echo ${foo[@]}
a b d e f

在這個例子中,我們刪除了陣列中的第三個元素,下標爲 2。記住,陣列下標開始於 0,而不是 1!也要注意陣列元素必須用引號引起來爲的是防止 shell 執行路徑名展開操作。

有趣地是,給一個數組賦空值不會清空陣列內容:

[me@linuxbox ~]$ foo=(a b c d e f)
[me@linuxbox ~]$ foo=
[me@linuxbox ~]$ echo ${foo[@]}
b c d e f

任何沒有下標的對陣列變數的參照都指向陣列元素 0:

[me@linuxbox~]$ foo=(a b c d e f)
[me@linuxbox~]$ echo ${foo[@]}
a b c d e f
[me@linuxbox~]$ foo=A
[me@linuxbox~]$ echo ${foo[@]}
A b c d e f

關聯陣列

關聯陣列使用字串而不是整數作爲陣列索引。這種功能給出了一種有趣的新方法來管理數據。例如,我們可以建立一個叫做「colors」的陣列,並用顏色名字作爲索引。

declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"

不同於整數索引的陣列,僅僅參照它們就能建立陣列,關聯陣列必須用帶有 -A 選項的 declare 命令建立。

存取關聯陣列元素的方式幾乎與整數索引陣列相同:

echo ${colors["blue"]}

組命令和子 shell

bash 允許把命令組合在一起。可以通過兩種方式完成;要麼用一個 group 命令,要麼用一個子 shell。這裏是每種方式的語法範例:

組命令:

{ command1; command2; [command3; ...] }

子 shell:

(command1; command2; [command3;...])

這兩種形式的不同之處在於,組命令用花括號把它的命令包裹起來,而子 shell 用括號。值得注意的是,鑑於 bash 實現組命令的方式,花括號與命令之間必須有一個空格,並且最後一個命令必須用一個分號或者一個換行符終止。