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:13bash
before"${a[@]}"
that you're quoting from my first command is what gets put into$0
in thebash -c
script. It's used in diagnostic messages (errors) that this shell may produce. Without thebash
string there, the first element ofa
would be put into$0
and 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:18find
in 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