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
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:37find . -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 putb="${a[*]}"after xargs. Could you please suggest change? – Porcupine Feb 26 '21 at 16:13bashbefore"${a[@]}"that you're quoting from my first command is what gets put into$0in thebash -cscript. It's used in diagnostic messages (errors) that this shell may produce. Without thebashstring there, the first element ofawould be put into$0and would not be part of"$@". – Kusalananda Feb 26 '21 at 16:16_– Porcupine Feb 26 '21 at 16:17bash, as it's used in error messages, as I mentioned. – Kusalananda Feb 26 '21 at 16:18findin your question. I would dofind . -name '*.md' -exec bash -c 'for name; do echo "$name"; done' bash {} +. There is no need for passing arrays or usingxargs. – Kusalananda Feb 26 '21 at 16:19