12

I don't know why I can't use env array variable inside a script ?
In my ~/.bashrc or ~/.profile

export HELLO="ee"
export HELLOO=(aaa bbbb ccc)

in a shell :

> echo $HELLO
ee
> echo $HELLOO
aaa
> echo ${HELLOO[@]}
aaa bbbb ccc

in a script :

#!/usr/bin/env bash
echo $HELLO
echo $HELLOO
echo ${HELLOO[@]}
---
# Return 
ee

Why ?

22

A bash array can not be an environment variable as environment variables may only be key-value string pairs.

You may do as the shell does with its $PATH variable, which essentially is an array of paths; turn the array into a string, delimited with some particular character not otherwise present in the values of the array:

$ arr=( aa bb cc "some string" )
$ arr=$( printf '%s:' "${arr[@]}" )
$ printf '%s\n' "$arr"
aa:bb:cc:some string:

Or neater,

arr=( aa bb cc "some string" )
arr=$( IFS=:; printf '%s' "${arr[*]}" )
export arr

The expansion of ${arr[*]} will be the elements of the arr array separated by the first character of IFS, here set to :. Note that if doing it this way, the elements of the string will be separated (not delimited) by :, which means that you would not be able to distinguish an empty element at the end, if there was one.


An alternative to passing values to a script using environment variables is (obviously?) to use the command line arguments:

arr=( aa bb cc )

./some_script "${arr[@]}"

The script would then access the passed arguments either one by one by using the positional parameters $1, $2, $3 etc, or by the use of $@:

printf 'First I got "%s"\n' "$1"
printf 'Then  I got "%s"\n' "$2"
printf 'Lastly there was "%s"\n' "$3"

for opt in "$@"; do
    printf 'I have "%s"\n' "$opt"
done
8
  • btw, printf cycles through its args, printf 'I have "%s"\n' "$@".
    – jthill
    Oct 6 '18 at 2:21
  • See fish or rc and derivatives for shells that can export arrays (each with their own encoding understood by themselves only). Nov 1 '18 at 11:02
  • Another aproach is to use export array_exported="$(printf '%q ' "${array[@]}")" and re-import (in the same locale) with typeset -a "array=($array_exported)" or eval, though like in your approach, that wouldn't preserve the indices of sparse arrays. Nov 1 '18 at 11:05
  • @StéphaneChazelas I see what you're getting at now. Good. Yes.
    – Kusalananda
    Nov 1 '18 at 11:18
  • Re: printf %q, that should be ((${#array[@]} == 0)) || printf '%q '..., or it would be wrong for an array with no element. Anyway, using typeset -p array would be better and preserve indices. That rings a bell, so there may be a duplicate of this Q&A here. Nov 1 '18 at 11:25
3

Arrays are bash specific. Environment variables are name-value pairs.

Read the specifications on environment variables, which says, in part:

The value of an environment variable is a string of characters. For a C-language program, an array of strings called the environment shall be made available when a process begins. The array is pointed to by the external variable environ, which is defined as:

extern char **environ;

These strings have the form name=value; names shall not contain the character '='.

4
  • Ok thk, in short, what I have to do ?
    – lescaudr
    Sep 19 '17 at 4:16
  • @MathieuLescaudron, um...don't use arrays for things you want to pass via environment variables? I don't really know what you're trying to achieve. You asked why you can't do a specific thing; I explained. The inability to pass arrays via environment variables has never stopped me.
    – Wildcard
    Sep 19 '17 at 4:22
  • thk, I now use string.
    – lescaudr
    Sep 19 '17 at 4:49
  • OP has a clear objective which can be solved with BASH_ENV environment script. So a command can be executed like BASH_ENV=~/array.sh ~/command.sh. So basically the bash evironment can be declared inside bash script and declarations within the script can therefore be called environment declarations. Oct 23 at 21:41
-1

Current Array Export Situation 10/2021

Array export is not fully implemented yet. You can clone the source code with command git clone https://git.savannah.gnu.org/git/bash.git ~/bash-src. Look into the bash source ~/bash-src/config-top.h for the commented line 154:

/* Define to 1 if you want to be able to export indexed arrays to processes
   using the foo=([0]=one [1]=two) and so on */
/* #define ARRAY_EXPORT 1 */

and furthermore the code section in ~/bash-src/variables.c at line 429 which says

#if defined (ARRAY_VARS)
#  if ARRAY_EXPORT
      /* Array variables may not yet be exported. */
      if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')')
    {
      string_length = 1;
      temp_string = extract_array_assignment_list (string, &string_length);
      temp_var = assign_array_from_string (name, temp_string, 0);
      FREE (temp_string);
      VSETATTR (temp_var, (att_exported | att_imported));
      array_needs_making = 1;
    }
      else
#  endif /* ARRAY_EXPORT */
#endif

so basically some more work has to be put into this issue.

Workaround

Meanwhile you can export the BASH_ENV variable which can point to an environment script. I put mine into /etc/bash.environment and declare system-wide arrays there. Your ~/.bashrc could contain something like export BASH_ENV="~/.bash.environment", now every bash process executed by the current user will source this file.

As @they mentioned below an according ~/.bashrc configuration to take effect on interactive AND noninteractive shells is needed:

[ -r "~/.bash.environment" ] \
&& source "~/.bash.environment" \
&& export BASH_ENV="~/.bash.environment"

And finally your environment:

# ~/.bash.environment
export HELLO="ee"
export HELLOO=(aaa bbbb ccc)

Best wishes

1
  • 1
    Note that BASH_ENV is only used for noninteractive shells, i.e. scripts.
    – they
    Oct 22 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.