-1

There are several questions, which solve the problem, but I wanted to try the following approach:

In this question I am basically having an array as an environment variable and then trying to store the string into separate array elements.

a=('Apple Tomato' 'Banana Carrot') bash -c \
'b=($(echo "${a}")); echo -e "${b[0]}\n"; echo "${b[1]}";'

Output

(Apple

Tomato

Desired Output:

Apple Tomato

Banana Carrot

An observation:

Also, if the original array had double quotes inside single quotes array elements, will the quotes be preserved. For example: a=('Apple "Tomato"' 'Banana "Carrot"')

Porcupine
  • 1,892

1 Answers1

5

Environment variables are simple key-value pairs of strings. An array can not be an environment variable.

However, you may pass the values of your a array to your bash -c script:

bash -c 'printf "%s\n" "$@"' bash "${a[@]}"

or, if you want to call the array b in the script:

bash -c 'b=( "$@" ); printf "%s\n" "${b[@]}"' bash "${a[@]}"

In both of these cases, the elements of array a are passed on the command line of the script. This means that they will show up in "$@" (in "$1", "$2", etc.) inside your bash -c script.

What's happening in your question is that the command

a=('Apple Tomato' 'Banana Carrot') bash -c '...'

sets the variable a to the string (Apple Tomato Banana Carrot). This is the value of the environment variable a in the bash -c script:

$ a=('Apple Tomato' 'Banana Carrot') bash -c 'printf "%s\n" "$a"'
(Apple Tomato Banana Carrot)

If you really needed to pass the data as an environment variable, you may do so by deciding on a delimiter and then flattening your array into a single string.

For example, using :

IFS=:
b="${a[*]}" bash -c 'set -f; IFS=:; a=( $b ); printf "%s\n" "${a[@]}"'

This constructs the string Apple Tomato:Banana Carrot and creates the environment variable b with this string as its value for the bash -c script.

That script then splits b on : again, and assigns the split up words to its own a array.

I need to use set -f in the script to avoid invoking filename globbing on the split up words when using $b unquoted.

You then also want to restore the original value of IFS in both the bash -c and the parent shell (you may want store the old value in a variable to make this easier). You may also want to enable filename globbing again in the bash -c script, with set +f.

ifs=$IFS; IFS=:
b="${a[*]}" bash -c 'set -f; ifs=$IFS; IFS=:; a=( $b ); IFS=$ifs; unset ifs; set +f; printf "%s\n" "${a[@]}"'
IFS=$ifs; unset ifs
Kusalananda
  • 333,661
  • I am completely unfamiliar with this construct bash "${a[@]}". I read your explanation, but is it like invoking a subshell and then doing variable expansion? Without invoking a subshell just typing "${a[@]}" in bash does expansion, but returns command not found. If its really invoking a subshell, then how is the variable (the expansion) gets passed to parent shell? – Porcupine Feb 26 '21 at 15:37
  • Actually I am having this subshell invocation with xargs as follows: find . -name "*.md"| xargs -0 -I "{}" b="${a[*]}" bash -c 'set -f; ifs=$IFS; IFS=:; a=( $b ); IFS=$ifs; unset ifs; set +f; printf "%s\n" "${a[@]}"' _ "{}" \; but i am unable to put b="${a[*]}" after xargs. Could you please suggest change? – Porcupine Feb 26 '21 at 16:13
  • @Porcupine The bash before "${a[@]}" that you're quoting from my first command is what gets put into $0 in the bash -c script. It's used in diagnostic messages (errors) that this shell may produce. Without the bash string there, the first element of a would be put into $0 and would not be part of "$@". – Kusalananda Feb 26 '21 at 16:16
  • So it can be anything like _ – Porcupine Feb 26 '21 at 16:17
  • @Porcupine I would let it be bash, as it's used in error messages, as I mentioned. – Kusalananda Feb 26 '21 at 16:18
  • @Porcupine You never said anything about find in your question. I would do find . -name '*.md' -exec bash -c 'for name; do echo "$name"; done' bash {} +. There is no need for passing arrays or using xargs. – Kusalananda Feb 26 '21 at 16:19
  • @Porcupine See also https://unix.stackexchange.com/questions/321697 – Kusalananda Feb 26 '21 at 16:20