Bash 支持關聯數組(associative arrays),可使用任意的字符串、或者整數做爲下標來訪問數組元素。
關聯數組的下標和值稱爲鍵值對,它們是一一對應關係,鍵是惟一的,值能夠不惟一。shell
要使用關聯數組以前,須要用 declare -A array_name
來進行顯式聲明 array_name 變量爲關聯數組。express
查看 help declare 對 -A
選項的說明以下:數組
-A
to make NAMEs associative arrays (if supported)
例以下面的語句定義了一個名爲 filetypes 的關聯數組,併爲數組賦值:bash
$ declare -A filetypes=([txt]=text [sh]=shell [mk]=makefile) $ filetypes[c]="c source file"
在使用數組名進行賦值時,須要用小括號 ()
把全部的值括起來。測試
在關聯數組裏面,用方括號 []
括起來的值是 key。
爲方括號 []
賦予的值是該 key 對應的 value。
不一樣的鍵值對之間用空格隔開。注意不是用逗號隔開。ui
也可使用 filetypes[key]=value
的方式單獨爲指定的關聯數組元素賦值。
若是所給的 key 以前不存在,bash 會自動建立它。
若是已經存在,則修改它的值爲 value 對應的值。lua
基於前面定義的 filetypes 這個數組名:code
${!filetypes[*]}
:獲取關聯數組的全部鍵名,注意在 filetypes 前面有一個感嘆號 ‘!’。遞歸
$ echo ${!filetypes[*]} txt sh c mk
${!filetypes[@]}
: 獲取關聯數組的全部鍵名。後面會說明使用 *
和 @
的區別。索引
$ echo ${!filetypes[@]} txt sh c mk
${filetypes[*]}
:獲取關聯數組的全部值。相比於獲取鍵名的表達式,少了前面的感嘆號 ‘!’。
$ echo ${filetypes[*]} text shell c source file makefile
${filetypes[@]}
:獲取關聯數組的全部值。
$ echo ${filetypes[@]} text shell c source file makefile
${#filetypes[*]}
:獲取關聯數組的長度,即元素個數。注意在 filetypes 前面有一個井號 ‘#’。
$ echo ${#filetypes[*]} 4
${#filetypes[@]}
:獲取關聯數組的長度,即元素個數
$ echo ${#filetypes[@]} 4
${filetypes[key]}
:獲取 key 這個鍵名對應的值。注意大括號 {}
是必須的。
$ echo ${filetypes[sh]} shell $ echo $filetypes[sh] [sh] # 能夠看到,不加大括號時,並不能獲取到數組元素的值
查看 man bash 的 Arrays 小節,說明了這幾個表達式的含義,同時還提到使用 *
和 @
的區別,貼出具體的區別以下:
If the word is double-quoted,${name[*]}
expands to a single word with the value of each array member separated by the first character of the IFS special variable, and${name[@]}
expands each element of name to a separate word. When there are no array members,${name[@]}
expands to nothing.
${!name[@]}
and${!name[*]}
expand to the indices assigned in array variable name. The treatment when in double quotes is similar to the expansion of the special parameters @ and * within double quotes.
即,使用 *
時,若是用雙引號把整個表達式括起來,例如寫爲 "${!name[*]}"
、或者 "${name[*]}"
,那麼會把全部值合併成一個字符串。
使用 @
時,若是用雙引號把整個表達式括起來,例如寫爲 "${!name[@]}"
、或者 "${name[@]}"
,那麼會獲得一個字符串數組。
每一個數組元素會用雙引號括起來,因此數組元素自身的空格不會致使拆分紅幾個單詞。
具體以下面的例子所示,這也是遍歷數組元素的例子:
$ for key in "${filetypes[*]}"; do echo "****:" $key; done ****: text shell c source file makefile $ for key in "${filetypes[@]}"; do echo "@@@@:" $key; done @@@@: text @@@@: shell @@@@: c source file @@@@: makefile
能夠看到,"${filetypes[*]}"
只產生一個字符串,for 循環只遍歷一次。
而 "${filetypes[@]}"
產生了多個字符串,for 循環遍歷屢次,是一個字符串數組。
並且所給的 "c source file" 這個字符串沒有被空格隔開成幾個單詞。
上面的例子也演示瞭如何用 for
命令來遍歷數組元素。
可使用 declare -p
命令來查看數組具體的鍵值對關係:
$ declare -p filetypes declare -A filetypes='([txt]="text" [sh]="shell" [c]="c source file" [mk]="makefile" )'
Bash 只支持一維數組 (one-dimensional indexed array),不支持二維數組。
聲明一維數組的方式是:declare -a array_name
。
因爲 bash 不要求明確指定變量的類型,其實不聲明也能夠,按數組的方式直接賦值給變量便可。
查看 help declare 對 -a
選項的說明以下:
-a
to make NAMEs indexed arrays (if supported)
使用 declare -a
聲明的數組,默認以數字做爲數組下標,並且不須要指定數組長度。
其賦值方式說明以下:
array=(value1 value2 value3 ... valueN):這種方式從數組下標 0 開始爲數組元素賦值,不一樣值之間用空格隔開,所給的值能夠是數字、字符串等。
$ declare -a array=(1 2 "30" "40" 5) $ echo ${array[@]} 1 2 30 40 5
array=([0]=var1 [1]=var2 [2]=var3 ... [n]=varN):這種方式顯式提供數組下標,指定爲該元素賦值,所給的數組下標能夠不連續。
$ declare -a array=([0]=1 [1]=2 [3]="30" [6]="60" [9]=9) $ echo ${array[@]} # 用 ${array[@]} 獲取全部數組元素的值 1 2 30 60 9 $ echo ${array[5]} # 上面賦值的時候,跳過了數組下標 5,因此它對應的值爲空 $ declare -p array # 使用 declare -p 命令查看,會打印出被賦值的全部元素 declare -a array='([0]="1" [1]="2" [3]="30" [6]="60" [9]="9")'
array[0]=value1; array[1]=value2; ...; array[n]=varN:這種方式是單獨爲數組元素賦值。
$ unset array; declare -a array $ array[0]=0; array[1]=1; array[7]="70" $ declare -p array declare -a array='([0]="0" [1]="1" [7]="70")'
一維數組的其餘用法和前面文章介紹的關聯數組用法同樣。
例如,能夠用 ${array[@]}
獲取全部數組元素的值,用 ${#array[@]}
獲取數組的元素個數,等等。
能夠參考下面的代碼片斷來遍歷一維數組元素:
for item in "${array[@]}"; do echo $item done
一維數組經過正整數來索引數組元素。
若是提供負整數的下標值,那麼它具備特殊含義,表示從數組末尾開始往前索引。
例如,array[-1]
會索引到數組的最後一個元素,array[-2]
索引到數組的倒數第二個元素,依此類推。
具體舉例說明以下:
$ declare -a array=([0]=0 [1]=1 [2]="20" [3]=3) $ echo ${array[-1]}, ${array[-3]} 3, 1
注意:雖然 declare -a
聲明的數組要用數字做爲數組下標,可是使用字符串做爲數組下標並不會報錯。
實際測試有一些比較古怪的地方。具體舉例以下:
$ declare -a array=([0]=0 [1]=1 [2]="20" [3]=3) $ array[index]=1000 $ echo ${array[index]} 1000 $ array[new]=2000 $ echo ${array[index]} 2000 $ echo ${array[new]} 2000 $ declare -p array declare -a array='([0]="2000" [1]="1" [2]="20" [3]="3")'
能夠看到,爲 array[index]
元素賦值,沒有報錯,使用 ${array[index]}
能夠正常獲取到它的值。
可是爲 array[new]
賦值爲 2000 後,使用 ${array[index]}
打印 index 這個字符串下標對應的數組元素值,發現變成了 2000,跟 ${array[new]}
打印的值同樣。
看起來,就像是這兩個字符串下標關連到同一個數組元素。
實際上,它們都對應到數組元素 0。能夠看到,上面的 declare -p array
命令打印出 [0]
這個元素值變成了 2000。
查看 man bash 的 Arrays 部分,說明以下:
Indexed arrays are referenced using integers (including arithmetic expressions) and are zero-based;An indexed array is created automatically if any variable is assigned to using the syntax name[subscript]=value.
The subscript is treated as an arithmetic expression that must evaluate to a number.Referencing an array variable without a subscript is equivalent to referencing the array with a subscript of 0.
即,indexed array 的下標必定是數字、或者是通過算術表達式 (arithmetic expressions) 計算獲得的數字。
若是沒有提供數組下標,默認會使用數組下標 0。
因爲 bash 的算術表達式在獲取變量值時,不須要使用 $
符號,因此上面的 array[index]
實際上至關於 array[$index]
,也就是獲取 index 變量的值來做爲數組下標。
若是所給的 index 變量沒有值,就至關於沒有提供數組下標,默認使用數組下標 0,因此爲 array[index]
賦值,其實是爲 array[0]
賦值。
同理,爲 array[new]
賦值,也是爲 array[0]
賦值,會看到 array[index]
的值也跟着改變。
若是 index 變量的值不是 0,並且 new 變量沒有值,那麼爲 array[index]
賦值,將不會影響到 array[new]
。
在上面例子的基礎上,繼續執行下面語句:
$ index=1 $ array[index]=100 $ echo "array[index] = ${array[index]}, array[1] = ${array[1]}" array[index] = 100, array[1] = 100 $ array[new]=900 $ echo "array[new] = ${array[new]}, array[0] = ${array[0]}, array[index]=${array[index]}" array[new] = 900, array[0] = 900, array[index]=100 $ recurse=index $ array[recurse]=500 $ echo "array[index] = ${array[index]}, array[recurse] = ${array[recurse]}, array[1] = ${array[1]}" array[index] = 500, array[recurse] = 500, array[1] = 500
能夠看到,將 index 變量賦值爲 1,修改 array[index]
的值,則改變的是數組下標 1 對應的元素、也就是 array[1]
的值。
即至關於用 $index
獲取該變量的值來做爲數組下標。
此時,因爲沒有爲 new 變量賦值,修改 array[new]
的值仍是關連到 array[0]
,不會影響到 array[index]
。
若是將變量賦值爲字符串,那麼會往下遞歸獲取該字符串對應的變量值。
上面將 recurse 賦值爲 "index" 字符串,修改 array[recurse]
的值,能夠看到 array[1]
的值被改變了。
即至關於先用 $recurse
獲取 recurse 變量的值是 "index",發現是字符串,繼續把 "index" 字符串做爲變量名。
用 $index
來獲取 index 變量的值是 1,最終使用 1 做爲數組下標。