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/04/14 14:27]
thebonsai Don't tread version 4 special - it has been around for a long time now
syntax:arrays [2018/04/20 06:45] (current)
tomroche add text on array copying
Line 49: Line 49:
 |''​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''​ |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. |
 +
 +As an example, and for use below, let's declare our ''​NAMES''​ array as described [[#​purpose|above]]:​
 +
 +    declare -a NAMES=('​Peter'​ '​Anna'​ '​Greg'​ '​Jan'​)
  
 ==== Storing values ==== ==== Storing values ====
Line 54: Line 58:
 Storing values in arrays is quite as simple as storing values in normal variables. Storing values in arrays is quite as simple as storing values in normal variables.
  
-^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''​ |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. 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\ ...)''​ |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. ​                                                                                                                                                                                                                                                                                                                                                                                                                                         | 
 +| ''​ARRAY=("​${ANOTHER_ARRAY[@]}"​)'' ​ | Copy ANOTHER_ARRAY to ARRAY, copying each element. ​                                                                                                                                                                                                                                                                                                                                                                                                       ​|
  
 As of now, arrays can't be exported. As of now, arrays can't be exported.
Line 147: Line 152:
 The method above, walking through an array by just knowing its number of elements, only works for arrays where all elements are set, of course. If one element in the middle is removed, then the calculation is nonsense, because the number of elements doesn'​t correspond to the highest used index anymore (we call them "//​sparse arrays//"​). The method above, walking through an array by just knowing its number of elements, only works for arrays where all elements are set, of course. If one element in the middle is removed, then the calculation is nonsense, because the number of elements doesn'​t correspond to the highest used index anymore (we call them "//​sparse arrays//"​).
  
 +Now, suppose that you want to replace your array ''​sentence''​ with the values in the [[#​purpose|previously-declared array]] ''​NAMES''​ . You might think you could just do
 +
 +<​code>​
 +$ unset sentence ; declare -a sentence=NAMES
 +$ echo ${#​sentence[@]}
 +1
 +# omit calculating max_index as above, and iterate as one-liner
 +$ for ((i = 0; i < ${#​sentence[@]};​ i++)); do  echo "​Element $i: '​${sentence[i]}'"​ ; done
 +Element 0: '​NAMES'​
 +</​code>​
 +
 +Obviously that's wrong. What about
 +
 +<​code>​
 +$ unset sentence ; declare -a sentence=${NAMES}
 +</​code>​
 +
 +? Again, wrong:
 +
 +<​code>​
 +$ echo ${#​sentence[*]}
 +1
 +$ for ((i = 0; i < ${#​sentence[@]};​ i++)); do  echo "​Element $i: '​${sentence[i]}'"​ ; done
 +Element 0: '​Peter'​
 +</​code>​
 +
 +So what's the **right** way? The (slightly ugly) answer is, reuse the enumeration syntax:
 +
 +<​code>​
 +$ unset sentence ; declare -a sentence=("​${NAMES[@]}"​)
 +$ echo ${#​sentence[@]}
 +4
 +$ for ((i = 0; i < ${#​sentence[@]};​ i++)); do  echo "​Element $i: '​${sentence[i]}'"​ ; done
 +Element 0: '​Peter'​
 +Element 1: '​Anna'​
 +Element 2: '​Greg'​
 +Element 3: '​Jan'​
 +</​code>​
  
 ==== Associative (Bash 4) ==== ==== Associative (Bash 4) ====
Line 340: Line 383:
 ==== 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 390:
 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 402:
 + 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)]=