lonix
lonix

Reputation: 20757

Pass array from .env to docker-compose.yml to Dockerfile to bash script

I created a custom docker container, which calls a startup script. That script requires some data, which is stored in my .env file.

All variables required by all files are stored in .env, and that is where I want to keep it. I can pass variables this way without error... it's only arrays that I can't pass correctly.

.env:

FOO=1                # blah
BAR='bar'            # this does blah
MYARRAY=(
  hello              # blah
  world              # blah
)

docker-compose.yml:

mycontainer:
  env_file: .env
  build:
    context: .
    args:                           # pass variables into dockerfile
      FOO: ${FOO}
      MYARRAY: ${MYARRAY}

Dockerfile:

FROM some_app
ARG FOO
ARG MYARRAY
ENV \
  FOO=$FOO \
  MYARRAY=$MYARRAY                # pass variables into script
CMD [ "myscript.sh" ]

myscript.sh:

#!/bin/bash
set -Eeuo pipefail
echo "$FOO"                                        # works
for i in "${MYARRAY[@]}"; do echo "$i"; done       # <---- problem is here

The array does not arrive intact in the script - it arrives as "(". This is because it is "translated" from ini to yaml to dockerfile syntax to bash.

How do I escape/format the stuff in .env so that it arrives in the bash script correctly?

Upvotes: 4

Views: 4526

Answers (1)

KamilCuk
KamilCuk

Reputation: 141200

Use declare -p output and transmit the array as plain text.

MYARRAY=(hello world)

Later in your script:

declare -a MYARRAY="$MYARRAY"
printf "%s\n" "${MYARRAY[@]}"

Bash arrays is an extension by bash, it's not supported anywhere else. Environment variables can contain only text, a value. Pass anything more complicated using text properly escaped and extracted with declare -p (or even functions with declare -f). For hard cases you can prepare (or even autogenerate from some script) the array with the help of printf "%q":

hardarray=('!@#\''\' "space space")
printf "%q" "$(declare -p hardarray | cut -d= -f2-)" # put the output in .env file
# then add in your .env file:
hardarray=\(\[0\]=\"\!@#\\\\\\\\\"\ \[1\]=\"space\ space\"\)
# then later read the array in your script:
declare -a hardarray="$hardarray"

I believe passing multiline strings via env_file in docker-compose is impossible. I would just advise to generate it from a shell script (but sadly, this adds another stage to the build process).

Upvotes: 5

Related Questions