Reputation: 17
I fail to understand what is happening between these two array creation, tested on cygwin GNU bash
$ array=('hello world' how are you)
$ echo $array
'hello world' <----- This is expected
EDIT : As chepner pointed it out the output is
hello world <----- no ''
Now with variable assignment as an intermediate step
$ words="'hello world' how are you"
$ echo $words
'hello world' how are you
$ array=($words)
$ echo $array
'hello <----- Why was it split with ' '?
Upvotes: 2
Views: 6690
Reputation: 6649
What about something like
$ array=($(echo -e $'a a\nb b' | tr ' ' '§')) && array=("${array[@]//§/ }") && echo "${array[@]/%/ INTERELEMENT}"
a a INTERELEMENT b b INTERELEMENT
Upvotes: 0
Reputation: 440337
codeforester's helpful answer explains the issue well.
As for a solution:
Note: If the input you're dealing with doesn't actually have embedded quoting to demarcate elements, simply use readarray -t array < <(...)
as is, where (...
) represents the output-producing command whose lines should be captured as the individual elements of an array.
xargs
generally understands shell quoting in literal input (except for escaped, embedded quotes):
words="'hello world' how are you"
echo "$words" | xargs -n 1 printf '%s\n'
hello world
how
are
you
Note how hello world
was recognized as a single argument, and how its enclosing '
instances were removed.
To utilize this when creating an array in bash
(assumes Bash 4.x due to readarray
, but it's possible to make it work in Bash 3.x[1]
):
words="'hello world' how are you"
readarray -t array < <(xargs -n 1 printf '%s\n' <<<"$words")
declare -p array
which yields:
declare -a array=([0]="hello world" [1]="how" [2]="are" [3]="you")
(The enclosing "
instances are an artifact of the declare -p
output format - they have syntactic function, if you were to reuse the output as shell source code.)
[1] A Bash v3+ solution, using read
instead of readarray
:
words="'hello world' how are you"
IFS=$'\n' read -d '' -ra array < <(xargs -n 1 printf '%s\n' <<<"$words")
declare -p array
Upvotes: 3
Reputation: 19335
In the first case single quotes prevent word splitting to split hello world in two arguments, the single quotes are not echoed
$ array=('hello world' how are you)
$ echo $array
hello world
in the second, the quotes are string literal, arguments are split, this can't be seen because echo displays all arguments, if you use printf "<%s>\n" $words
you will see better
$ words="'hello world' how are you"
$ echo $words
'hello world' how are you
$ array=($words)
$ echo $array
'hello
$ words="'hello world' how are you"
$ printf "<%s>\n" $words
<'hello>
<world'>
<how>
<are>
<you>
As said in comments, eval is dangerous, you must know what you are doing
$ eval "array=($words)"
$ printf "<%s>\n" "${array[@]}"
<hello world>
<how>
<are>
<you>
Upvotes: 0
Reputation: 43089
From Bash manual:
Referencing an array variable without a subscript is equivalent to referencing with a subscript of 0.
When you put single quotes inside double quotes as in:
words="'hello world' how are you"
the single quotes become a literal part of the string and hence won't prevent word split when you initialize the array with
array=($words)
wherein 0th element of the array would become 'hello
. To prevent word splitting in this case, do this:
array=("$words")
However, that wouldn't achieve your intention of making hello world
as the 0th element. The direct assignment array=('hello world' how are you)
is the right way of doing it.
See also:
Upvotes: 3
Reputation: 1148
"Referring to the content of a member variable of an array without providing an index number is the same as referring to the content of the first element, the one referenced with index number zero." From this page, last line of section 10.2.2
So
$ echo $array
is equivalent to
$ echo ${array[0]}
Upvotes: 0
Reputation: 6198
It's the dereferencing. Try this:
$ array=('hello world' how are you)
$ echo $array
hello world
$ echo ${array[@]}
hello world how are you
$ echo ${array[0]}
hello world
$ echo ${array[1]}
how
$ echo ${array[2]}
are
$ echo ${array[3]}
you
Upvotes: 0