Home > Back-end >  sliced arrays flatten to len=1?
sliced arrays flatten to len=1?

Time:11-18

I am pulling my hair out manipulating arrays in bash. I have an array of strings, which contain spaces. I would like an array containing all but the first element of my input array.

input=("first string" "second string" "third string")
echo ${#input[@]}
# len(input)=3
# get slice of all except for first element of input
slice=${input[@]:1}
echo ${#slice[@]}
# expect 2, but get 1
echo $slice
# second string third string
# slice should contain ("second string" "third string"), but instead is "second string third string"

Slicing the array clearly works to eliminate the first element, but the result appears to be a concatenation of all remaining strings, rather than an array. Is there a way to slice an array in bash and get an array as a result?

(sorry, I'm not new to bash, but I've never used it for much before, and I can't find any documentation showing why my slice is flattened)

CodePudding user response:

Indexes are reset, element 1 is now element 0:

slice=("${input[@]:1}")

Element and index are removed, the first element is now index 1, not index 0:

unset input[0]

${#slice[@]} or ${#input[@]} will now be 1 less than the previous value of ${#input[@]}. Starting out with three elements in slice, the values of "${!slice[@]}" and "${!input[@]}", will be 0 1 and 1 2 respectively (for either the first or second approach)

If you don't quote slice=("${input[@]:1}"), each array element is split on whitespace, creating many more elements.

CodePudding user response:

First off, you should always quote variable expansions. Be very wary of any solution that relies on unquoted expansions. ShellCheck.net is a great tool for catching bugs related to quoting (among many other issues).

To your specific issue, slice=${input[@]:1} does not do what you want. It defines a single scalar variable slice rather than an array, meaning the array expansion (denoted by the [@]) will first be munged into a single string using the current IFS. Here's a demo:

$ arr=(1 2 '3 4')
$ IFS=,
$ var="${arr[@]:1}"
$ echo "$var"
2,3 4

To instead declare and populate an array use the =() notation, like so:

$ var=("${arr[@]:1}")
$ printf '%s\n' "${var[@]}"
2
3 4
  • Related