Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
syntax:arrays [2013/03/03 11:18]
ormaaj Point out that = doesn't unset an associative attribute
syntax:arrays [2013/07/21 02:04] (current)
ormaaj [Bugs] More bugs fixed!!
Line 20: Line 20:
 Bash supports two different types of ksh-like one-dimensional arrays. **Multidimensional arrays are not implemented**. Bash supports two different types of ksh-like one-dimensional arrays. **Multidimensional arrays are not implemented**.
   * //Indexed arrays// use positive integer numbers as keys. Indexed arrays are **always sparse**, meaning indexes are not necessarily contiguous. All syntax used for both assigning and dereferencing indexed arrays is an [[syntax:​arith_expr | arithmetic evaluation context]] (see [[#​Referencing]]). As in C and many other languages, the numerical array indexes start at 0 (zero). Indexed arrays are the most common, useful, and portable type. Indexed arrays were first introduced to Bourne-like shells by ksh88. Similar, partially compatible syntax was inherited by many derivatives including Bash. Indexed arrays always carry the ''​-a''​ attribute.   * //Indexed arrays// use positive integer numbers as keys. Indexed arrays are **always sparse**, meaning indexes are not necessarily contiguous. All syntax used for both assigning and dereferencing indexed arrays is an [[syntax:​arith_expr | arithmetic evaluation context]] (see [[#​Referencing]]). As in C and many other languages, the numerical array indexes start at 0 (zero). Indexed arrays are the most common, useful, and portable type. Indexed arrays were first introduced to Bourne-like shells by ksh88. Similar, partially compatible syntax was inherited by many derivatives including Bash. Indexed arrays always carry the ''​-a''​ attribute.
-  * :V4: //​Associative arrays// (sometimes known as a "​hash"​ or "​dict"​) use arbitrary nonempty strings as keys. In other words, associative arrays allow you to look up a value from a table based upon its corresponding string label. **Associative arrays are always unordered**,​ they merely //​associate//​ key-value pairs. If you retrieve multiple values from the array at once, you can't count on them coming out in the same order you put them in. Associative arrays always carry the ''​-A''​ attribute, and unlike indexed arrays, Bash requires that they always be declared explicitly (as indexed arrays are the default, see [[#​Declaration | declaration]]). Associative arrays were first introduced in ksh93, and similar mechanisms were later adopted by Zsh and Bash version 4. These three are currently the only POSIX-compatible shells with any associative array support.+  * //​Associative arrays// (sometimes known as a "​hash"​ or "​dict"​) use arbitrary nonempty strings as keys. In other words, associative arrays allow you to look up a value from a table based upon its corresponding string label. **Associative arrays are always unordered**,​ they merely //​associate//​ key-value pairs. If you retrieve multiple values from the array at once, you can't count on them coming out in the same order you put them in. Associative arrays always carry the ''​-A''​ attribute, and unlike indexed arrays, Bash requires that they always be declared explicitly (as indexed arrays are the default, see [[#​Declaration | declaration]]). Associative arrays were first introduced in ksh93, and similar mechanisms were later adopted by Zsh and Bash version 4. These three are currently the only POSIX-compatible shells with any associative array support.
  
 ===== Syntax ===== ===== Syntax =====
Line 48: Line 48:
 |''​ARRAY[0]=''​ |Generally sets the first element of an **indexed** array. If no array ''​ARRAY''​ existed before, it is created. | |''​ARRAY[0]=''​ |Generally sets the first element of an **indexed** array. If no array ''​ARRAY''​ existed before, it is created. |
 |''​declare -a ARRAY''​ |Declares an **indexed** array ''​ARRAY''​. An existing array is not initialized. | |''​declare -a ARRAY''​ |Declares an **indexed** array ''​ARRAY''​. An existing array is not initialized. |
-|''​declare -A ARRAY''​ |:V4: Declares an **associative** array ''​ARRAY''​. This is the one and only way to create associative arrays. |+|''​declare -A ARRAY''​ |Declares an **associative** array ''​ARRAY''​. This is the one and only way to create associative arrays. |
  
 ==== Storing values ==== ==== Storing values ====
Line 56: Line 56:
 ^Syntax ^Description ^ ^Syntax ^Description ^
 |''​ARRAY[N]=VALUE''​ |Sets the element ''​N''​ of the **indexed** array ''​ARRAY''​ to ''​VALUE''​. **''​N''​ can be any valid [[syntax:​arith_expr | arithmetic expression]]**. | |''​ARRAY[N]=VALUE''​ |Sets the element ''​N''​ of the **indexed** array ''​ARRAY''​ to ''​VALUE''​. **''​N''​ can be any valid [[syntax:​arith_expr | arithmetic expression]]**. |
-|''​ARRAY[STRING]=VALUE''​ |:V4: Sets the element indexed by ''​STRING''​ of the **associative array** ''​ARRAY''​. |+|''​ARRAY[STRING]=VALUE''​ |Sets the element indexed by ''​STRING''​ of the **associative array** ''​ARRAY''​. |
 |''​ARRAY=VALUE''​ |As above. If no index is given, as a default the zeroth element is set to ''​VALUE''​. Careful, this is even true of associative arrays - there is no error if no key is specified, and the value is assigned to string index "​0"​. | |''​ARRAY=VALUE''​ |As above. If no index is given, as a default the zeroth element is set to ''​VALUE''​. Careful, this is even true of associative arrays - there is no error if no key is specified, and the value is assigned to string index "​0"​. |
-|''​ARRAY=(E1\ E2\ ...)''​ | Compound array assignment - sets the whole array ''​ARRAY''​ to the given list of elements indexed sequentially starting at zero. The array is unset before assignment unless the += operator is used. When the list is empty (''​ARRAY=()''​),​ the array will be set to an empty array. ​:V4: This method obviously does not use explicit indexes. An **associative array** can **not** be set like that! Clearing an associative array using ''​ARRAY=()''​ works. |+|''​ARRAY=(E1\ E2\ ...)''​ | Compound array assignment - sets the whole array ''​ARRAY''​ to the given list of elements indexed sequentially starting at zero. The array is unset before assignment unless the += operator is used. When the list is empty (''​ARRAY=()''​),​ the array will be set to an empty array. This method obviously does not use explicit indexes. An **associative array** can **not** be set like that! Clearing an associative array using ''​ARRAY=()''​ works. |
 |''​ARRAY=([X]=E1\ [Y]=E2\ ...)''​ |Compound assignment for indexed arrays with index-value pairs declared individually (here for example ''​X''​ and ''​Y''​). X and Y are arithmetic expressions. This syntax can be combined with the above - elements declared without an explicitly specified index are assigned sequentially starting at either the last element with an explicit index, or zero. | |''​ARRAY=([X]=E1\ [Y]=E2\ ...)''​ |Compound assignment for indexed arrays with index-value pairs declared individually (here for example ''​X''​ and ''​Y''​). X and Y are arithmetic expressions. This syntax can be combined with the above - elements declared without an explicitly specified index are assigned sequentially starting at either the last element with an explicit index, or zero. |
-|''​ARRAY=([S1]=E1\ [S2]=E2\ ...)''​ |:V4: Individual mass-setting for **associative arrays**. The named indexes (here: ''​S1''​ and ''​S2''​) are strings. |+|''​ARRAY=([S1]=E1\ [S2]=E2\ ...)''​ |Individual mass-setting for **associative arrays**. The named indexes (here: ''​S1''​ and ''​S2''​) are strings. |
 |''​ARRAY+=(E1\ E2\ ...)''​ |Append to ARRAY. | |''​ARRAY+=(E1\ E2\ ...)''​ |Append to ARRAY. |
  
Line 70: Line 70:
  
 ^Syntax ^Description ^ ^Syntax ^Description ^
-| ''​${ARRAY[N]}''​ | Expands to the value of the index ''​N''​ in the **indexed** array ''​ARRAY''​. If ''​N''​ is a negative number, it's treated as the offset from the maximum assigned index (can't be used for assignment) - 1 /:V4: 4.2-alpha) ​+| ''​${ARRAY[N]}''​ | Expands to the value of the index ''​N''​ in the **indexed** array ''​ARRAY''​. If ''​N''​ is a negative number, it's treated as the offset from the maximum assigned index (can't be used for assignment) - 1  
-| ''​${ARRAY[S]}''​ | :V4: Expands to the value of the index ''​S''​ in the **associative** array ''​ARRAY''​. |+| ''​${ARRAY[S]}''​ | Expands to the value of the index ''​S''​ in the **associative** array ''​ARRAY''​. |
 | ''"​${ARRAY[@]}"​\\ ${ARRAY[@]}\\ "​${ARRAY[*]}"​\\ ${ARRAY[*]}''​ | Similar to [[scripting:​posparams#​mass_usage| mass-expanding positional parameters]],​ this expands to all elements. If unquoted, both subscripts ''​*''​ and ''​@''​ expand to the same result, if quoted, ''​@''​ expands to all elements individually quoted, ''​*''​ expands to all elements quoted as a whole. | | ''"​${ARRAY[@]}"​\\ ${ARRAY[@]}\\ "​${ARRAY[*]}"​\\ ${ARRAY[*]}''​ | Similar to [[scripting:​posparams#​mass_usage| mass-expanding positional parameters]],​ this expands to all elements. If unquoted, both subscripts ''​*''​ and ''​@''​ expand to the same result, if quoted, ''​@''​ expands to all elements individually quoted, ''​*''​ expands to all elements quoted as a whole. |
 | ''"​${ARRAY[@]:​N:​M}"​\\ ${ARRAY[@]:​N:​M}\\ "​${ARRAY[*]:​N:​M}"​\\ ${ARRAY[*]:​N:​M}''​ | Similar to what this syntax does for the characters of a single string when doing [[syntax:​pe#​substring_expansion| substring expansion]],​ this expands to ''​M''​ elements starting with element ''​N''​. This way you can mass-expand individual indexes. The rules for quoting and the subscripts ''​*''​ and ''​@''​ are the same as above for the other mass-expansions. | | ''"​${ARRAY[@]:​N:​M}"​\\ ${ARRAY[@]:​N:​M}\\ "​${ARRAY[*]:​N:​M}"​\\ ${ARRAY[*]:​N:​M}''​ | Similar to what this syntax does for the characters of a single string when doing [[syntax:​pe#​substring_expansion| substring expansion]],​ this expands to ''​M''​ elements starting with element ''​N''​. This way you can mass-expand individual indexes. The rules for quoting and the subscripts ''​*''​ and ''​@''​ are the same as above for the other mass-expansions. |
Line 81: Line 81:
 ^Syntax ^Description ^ ^Syntax ^Description ^
 |''​${#​ARRAY[N]}''​ |Expands to the **length** of an individual array member at index ''​N''​ (**stringlength**) | |''​${#​ARRAY[N]}''​ |Expands to the **length** of an individual array member at index ''​N''​ (**stringlength**) |
-|''​${#​ARRAY[STRING]}''​ |:V4: Expands to the **length** of an individual associative array member at index ''​STRING''​ (**stringlength**) |+|''​${#​ARRAY[STRING]}''​ | Expands to the **length** of an individual associative array member at index ''​STRING''​ (**stringlength**) |
 |''​${#​ARRAY[@]}''​\\ ''​${#​ARRAY[*]}''​|Expands to the **number of elements** in ''​ARRAY''​ | |''​${#​ARRAY[@]}''​\\ ''​${#​ARRAY[*]}''​|Expands to the **number of elements** in ''​ARRAY''​ |
 |''​${!ARRAY[@]}''​\\ ''​${!ARRAY[*]}''​|Expands to the **indexes** in ''​ARRAY''​ since BASH 3.0| |''​${!ARRAY[@]}''​\\ ''​${!ARRAY[*]}''​|Expands to the **indexes** in ''​ARRAY''​ since BASH 3.0|
Line 91: Line 91:
 |''​unset -v ARRAY''​\\ ''​unset -v ARRAY[@]''​\\ ''​unset -v ARRAY[*]''​ |Destroys a complete array | |''​unset -v ARRAY''​\\ ''​unset -v ARRAY[@]''​\\ ''​unset -v ARRAY[*]''​ |Destroys a complete array |
 |''​unset -v ARRAY[N]''​|Destroys the array element at index ''​N''​ | |''​unset -v ARRAY[N]''​|Destroys the array element at index ''​N''​ |
-|''​unset -v ARRAY[STRING]''​|:V4: Destroys the array element of the associative array at index ''​STRING''​ |+|''​unset -v ARRAY[STRING]''​|Destroys the array element of the associative array at index ''​STRING''​ |
  
 It is best to [[commands/​builtin/​unset#​portability_considerations | explicitly specify -v]] when unsetting variables with unset. It is best to [[commands/​builtin/​unset#​portability_considerations | explicitly specify -v]] when unsetting variables with unset.
Line 340: Line 340:
 ==== Bugs ==== ==== Bugs ====
  
-  * Bash 4.2.* and earlier considers each chunk of a compound assignment, including the subscript for globbing. The subscript part is considered quoted, but any unquoted glob characters on the right-hand side of the ''​[...]=''​ will be clumped with the subscript and counted as a glob. Therefore, you must quote anything on the right of the ''​=''​ sign.  This is fixed in 4.3, so that each subscript assignment statement is expanded following the same rules as an ordinary assignment. This also works correctly in ksh93. <​code>​+  ​* **Fixed in 4.3** Bash 4.2.* and earlier considers each chunk of a compound assignment, including the subscript for globbing. The subscript part is considered quoted, but any unquoted glob characters on the right-hand side of the ''​[...]=''​ will be clumped with the subscript and counted as a glob. Therefore, you must quote anything on the right of the ''​=''​ sign.  This is fixed in 4.3, so that each subscript assignment statement is expanded following the same rules as an ordinary assignment. This also works correctly in ksh93. <​code>​
 $ touch '​[1]=a';​ bash -c '​a=([1]=*);​ echo "​${a[@]}"'​ $ touch '​[1]=a';​ bash -c '​a=([1]=*);​ echo "​${a[@]}"'​
 [1]=a [1]=a
Line 347: Line 347:
 1=a 1=a
 </​code>​ </​code>​
-  * In addition to the above globbing issue, assignments preceding "​declare"​ have an additional effect on brace and pathname expansion. <​code>​+  ​* **Fixed in 4.3** In addition to the above globbing issue, assignments preceding "​declare"​ have an additional effect on brace and pathname expansion. <​code>​
 $ set -x; foo=bar declare arr=( {1..10} ) $ set -x; foo=bar declare arr=( {1..10} )
 + foo=bar + foo=bar
Line 359: Line 359:
 + declare xy=foo + declare xy=foo
 </​code>​ Each word (the entire assignment) is subject to globbing and brace expansion. This appears to trigger the same strange expansion mode as ''​let'',​ ''​eval'',​ other declaration commands, and maybe more.  </​code>​ Each word (the entire assignment) is subject to globbing and brace expansion. This appears to trigger the same strange expansion mode as ''​let'',​ ''​eval'',​ other declaration commands, and maybe more. 
-  * Indirection combined with another modifier expands arrays to a single word. <​code>​+  ​* **Fixed in 4.3** Indirection combined with another modifier expands arrays to a single word. <​code>​
 $ a=({a..c}) b=a[@]; printf '<​%s>​ ' "​${!b}";​ echo; printf '<​%s>​ ' "​${!b/​%/​foo}";​ echo $ a=({a..c}) b=a[@]; printf '<​%s>​ ' "​${!b}";​ echo; printf '<​%s>​ ' "​${!b/​%/​foo}";​ echo
 <a> <b> <c> <a> <b> <c>
 <a b cfoo> <a b cfoo>
 </​code>​ </​code>​
-  * Process substitutions are evaluated within array indexes. Zsh and ksh don't do this in any arithmetic ​contextT. <​code> ​+  ​* **Fixed in 4.3** Process substitutions are evaluated within array indexes. Zsh and ksh don't do this in any arithmetic ​context. <​code> ​
 # print "​moo"​ # print "​moo"​
 dev=fd=1 _[1<​(echo moo >&​2)]= dev=fd=1 _[1<​(echo moo >&​2)]=