0

This is a very "popular" topic on stackoverflow and unfortunately I haven't been able to figure this out when looking at other questions. Anyways let's consider the following scenario. A function gets a bunch of string arguments like so: some_function "give some" "string arguments" The first thing this function does is put these args into an array so that for example array[0] gives "give some" and array[1] gives "string arguments"

Now lets say I have an array of strings some_array and want to call some_function on it. How do I "transform" that array to make it work?

Here are a few examples which do NOT work:

function print_args() {
  local arr=( "$@" )
  i=0;
  for item in "${arr[@]}"
  do
    echo "[$i] -> '$item'"
    (( i++ ))
  done
}

echo "example"
print_args "this is" "the desired" "behavior"
echo -e "----------------\n"

some_array=( "\"does NOT\""  "\"seem to\"" "\"work\"" )
stringified_array=$(printf "%s " "${some_array[@]}")
echo "stringified array: [$stringified_array]"

echo "1) passing \$some_array"
print_args $some_array
echo -e "---------------------------\n"

echo "2) passing \"\$some_array\""
print_args "$some_array"
echo -e "---------------------------\n"

echo "3) passing \$stringified_array"
print_args $stringified_array
echo -e "---------------------------\n"

echo "4) passing \"\$stringified_array\""
print_args "$stringified_array"
echo -e "---------------------------\n"

and here is the output

example
[0] -> 'this is'
[1] -> 'the desired'
[2] -> 'behavior'
----------------

stringified array: ["does NOT" "seem to" "work" ]
1) passing $some_array
[0] -> '"does'
[1] -> 'NOT"'
---------------------------

2) passing "$some_array"
[0] -> '"does NOT"'
---------------------------

3) passing $stringified_array
[0] -> '"does'
[1] -> 'NOT"'
[2] -> '"seem'
[3] -> 'to"'
[4] -> '"work"'
---------------------------

4) passing "$stringified_array"
[0] -> '"does NOT" "seem to" "work" '
---------------------------

I think I understand 1) and 2) and only tried them out of desperation. I believe I understand 4) as well. Now my big problem is that I don't understand what the heck is going on with 3) and more importantly how I can "stringify" my array so as to achieve what I want. An important note here is that I would like to try and avoid the use of eval.

Thanks!

MarkoPaulo
  • 474
  • 4
  • 19
  • 3
    [Use as little code as possible that still produces the same problem.](https://stackoverflow.com/help/mcve) – Cyrus Nov 18 '18 at 20:41
  • 1
    Add a shebang and then paste your script there: http://www.shellcheck.net/ – Cyrus Nov 18 '18 at 20:42

1 Answers1

2

You may expect that you are saying with 3):

print_args "does NOT" "seem to" "work"

but in reality 3) is equivalent to:

print_args '"does' 'NOT"' '"seem' 'to"' '"work"'

this is because the unquoted argument variable $stringified_array is split into words on IFS before it is passed to the function. The double quotes within the string is just a part of string and does not work to quote the whitespaces.

Try to see what happens by modifying line #16-#17 in your sample code with:

16c16
< stringified_array=$(printf "%s " "${some_array[@]}")
---
> stringified_array=$(printf "%s#" "${some_array[@]}")
17a18
> IFS=#

By assigning IFS to a delimiter which does not appear in your strings, you will be able to stringify your array safely, although there will be other solutions without stringifying the array.
Hope this helps.

tshiono
  • 21,248
  • 2
  • 14
  • 22