ChatGPT解决这个技术问题 Extra ChatGPT

Add a new element to an array without specifying the index in Bash

Is there a way to do something like PHPs $array[] = 'foo'; in bash vs doing:

array[0]='foo'
array[1]='bar'

U
U. Windl

Yes there is:

ARRAY=()
ARRAY+=('foo')
ARRAY+=('bar')

Bash Reference Manual:

In the context where an assignment statement is assigning a value to a shell variable or array index (see Arrays), the ‘+=’ operator can be used to append to or add to the variable's previous value.

Also:

When += is applied to an array variable using compound assignment (see Arrays below), the variable's value is not unset (as it is when using =), and new values are appended to the array beginning at one greater than the array's maximum index (for indexed arrays)


This works just fine with bash 3.2.48 (OS X 10.8.2). Note that ARRAY is just a placeholder for an actual variable name. Even if your array indices are not sequential, appending with += will simply assign to the highest index + 1.
Is there something like that in bash version 4.2.24(1)?
It is important to note, that ARRAY+=('foo') is way different than ARRAY+='foo', which appends the string 'foo' to the entry with the lowest(?) key.
According to wiki.bash-hackers.org/scripting/bashchanges, this syntax first appeared in version 3.1-alpha1.
@Jas: To access the entire array, you must use ${myarray[@]} - referencing an array variable as if it were a scalar is the same as accessing its element 0; in other words: $myarray is the same as ${myarray[0]}.
D
Dennis Williamson

As Dumb Guy points out, it's important to note whether the array starts at zero and is sequential. Since you can make assignments to and unset non-contiguous indices ${#array[@]} is not always the next item at the end of the array.

$ array=(a b c d e f g h)
$ array[42]="i"
$ unset array[2]
$ unset array[3]
$ declare -p array     # dump the array so we can see what it contains
declare -a array='([0]="a" [1]="b" [4]="e" [5]="f" [6]="g" [7]="h" [42]="i")'
$ echo ${#array[@]}
7
$ echo ${array[${#array[@]}]}
h

Here's how to get the last index:

$ end=(${!array[@]})   # put all the indices in an array
$ end=${end[@]: -1}    # get the last one
$ echo $end
42

That illustrates how to get the last element of an array. You'll often see this:

$ echo ${array[${#array[@]} - 1]}
g

As you can see, because we're dealing with a sparse array, this isn't the last element. This works on both sparse and contiguous arrays, though:

$ echo ${array[@]: -1}
i

Great stuff; never knew that substring-extraction syntax could be applied to arrays too; the rules, determined by trial and error, are (bash 3.2.48): ${array[@]: start[:count]} Returns count elems. or, if not specified, all remaining elems. starting at the following elem.: - If start >= 0: from the elem. whose index is >= start. - If start < 0: from the elem. whose index is (last array index + 1) - abs(start); CAVEAT: if abs(start) > (last array index + 1), a null string is returned. If count is specified, as many elements are returned, even if their indices are not contiguous from start.
@mklement: In Bash 4.2, you can use negative array subscripts to access elements counting from the end of the array. ${array[-1]}
That's good to know, thanks. OS X (as of 10.8.2) still uses 3.2.48, and stackoverflow.com/questions/10418616/… tells me that, unfortunately, "Apple use quite an old version of Bash, as they don't ship code that's licensed under GPL3."
Z
Zenexer
$ declare -a arr
$ arr=("a")
$ arr=("${arr[@]}" "new")
$ echo ${arr[@]}
a new
$ arr=("${arr[@]}" "newest")
$ echo ${arr[@]}
a new newest

nice for bash versions that do not support the semantics of += operator explained by e-t172
a good backward-compatible solution, but beware that if any of the existing elements have spaces in them, they will be split into multiple elements; use arr=("${arr[@]}" "new") if you have elements with spaces in them
This can also be used to push in front of the array, which is just what I need.
If your array has hundreds of long strings, then the += variant is probably much more efficient.
j
jww

If your array is always sequential and starts at 0, then you can do this:

array[${#array[@]}]='foo'

# gets the length of the array
${#array_name[@]}

If you inadvertently use spaces between the equal sign:

array[${#array[@]}] = 'foo'

Then you will receive an error similar to:

array_name[3]: command not found

Yes, you can, but the += syntax (see @e-t172's answer) is (a) simpler, and (b) also works with arrays that are non-contiguous and/or do not start with 0.
Honestly this solution (for me) is working better thant the "+=", because with the latter the length is sometimes wrong (increases by two when adding one element)... so I prefer this reply! :)
This also works in earlier versions of bash, before += was added, eg version 2
This also works when your elements have spaces in them - $arr += ($el) seemed to split the string by space and add each of the elements.
c
codeforester

With an indexed array, you can to something like this:

declare -a a=()
a+=('foo' 'bar')