1

For example, in the snippet below, (how) is it possible to make array2 identical to array1 while still using a str variable?

~$ { str='a "b c" d'; array1=(a "b c" d); array2=( $str )
  echo "${array1[1]} ${array1[2]}"
  echo "${array2[1]} ${array2[2]}"; }

b c d
"b c"
glarry
  • 914
  • 1
  • 7
  • 16
  • my output is different... – pLumo Jun 02 '20 at 12:43
  • you did not quote $str - even if "$str" you just give printable chars like \"b c\" and not actually quoted string "b c" (only eval would execute quotes) – alecxs Jun 02 '20 at 12:47
  • @pLumo Do you also get two different arrays? – glarry Jun 02 '20 at 12:47
  • Sure. The quotes are taken literal and have no special meaning for the variable, they are just a character like any other. While when assigning the array using quotes, the quotes are evaluated from your shell to separate the arguments. – pLumo Jun 02 '20 at 12:52
  • 1
    What are you trying to do in the end? Can you skip the string variable and just do array=(a "b c" d)? – ilkkachu Jun 02 '20 at 12:55
  • @ilkkachu I can, in some cases, but I still needed a simple way to get an array out of an otherwise correctly formatted variable. – glarry Jun 02 '20 at 12:58
  • str='a b[[:space:]]c d' should work too (bash) or can be converted automatically (before passing into $str) like string="b c"; string="${string//[[:space:]]/[[:space:]]}"; str="a $string d"; (will mask all space, tab, newline, linefeed, formfeed, vertical tab in $string) – alecxs Jun 02 '20 at 13:24

2 Answers2

2

Running str='a "b c" d', the quotes are taken literal and have no special meaning afterwards, they are just a character like any other and do not prevent word splitting anymore.

While when assigning the array using quotes, the quotes are evaluated from your shell before the assignment to prevent word splitting:

array1=(a "b c" d);

Btw: Using printf is a bit easier to showcase the issue then setting up an array and using a loop to echo the elements:

printf '%s\n' $str

You might use eval as a workaround, but I would not recommend doing that for any input you cannot 100% control or trust (user input, webscraping stuff, etc.):

eval "printf '%s\n' $str"
#or
eval "array2=( $str )"

Anyways, from your example, I see no reason to use an intermediate variable, just use arrays directly.

pLumo
  • 22,565
  • of course. Because the quotes are lost as special shell characters when you set up the variable. I mean it's easier to showcase the issue using printf then setting up an array and using a loop to echo the element. – pLumo Jun 02 '20 at 13:02
0

Yes, it is possible, by using eval.

Thank you all for confirming the type of quoting problem.

Simply use eval "array2=( $str )" instead of array2=( $str ).

Note, however, that using eval is often a bad idea.

glarry
  • 914
  • 1
  • 7
  • 16
  • 1
    Just don't use eval with any untrusted input. It would process all expansions and e.g. semicolons. if str='$(evilcmd) foo', then eval "array2=( $str )" would run evilcmd and put the output in array2 – ilkkachu Jun 02 '20 at 13:03
  • Thank you for the warning. Actually your comment is a very important addition to this answer. – glarry Jun 02 '20 at 13:06