Reputation: 2673
I am trying to dereference the value of environment variable using parameter expansion $@
, but it doesn't seem to work.
I need to call a shell script with certain arguments. The list of arguments contain environment variables, and the environment variables are expected to be present where the shell script is to be executed. I do not know the list of commands before hand, so I am expanding those list of commands using $@
. However, the script is not able to de-reference the value of environment variables.
A minimal setup which explains my problem can be done as below.
FROM alpine:3.10
ENV MY_VAR=production
WORKDIR /app
COPY run.sh .
ENTRYPOINT [ "sh", "run.sh" ]
#!/bin/sh
echo "Value of MY_VAR is" $MY_VAR
echo "Begin"
$@
echo "Done"
I can build the image using docker build . -t env-test
. When I run it using docker run env-test:latest 'echo $MY_VAR'
, I get the below output.
Value of MY_VAR is production
Begin
$MY_VAR
Done
While the output that I am expecting is:
Value of MY_VAR is production
Begin
production
Done
SideNote: In actuality I am trying to run it using a compose file like below:
version: '3'
services:
run:
image: env-test:latest
command: echo $$MY_VAR
but it again gives me the similar result.
Upvotes: 1
Views: 1920
Reputation: 307
There are a more ways to skin this particular cat:
me@computer:~$ docker run -it --rm ubuntu:20.04 bash -c 'echo $HOSTNAME'
e610946f50c1
Here, we're calling on bash inside the container to process everything inside the single quotes, so variable substitution and/or expansion isn't applied by your shell, but by the shell inside the container.
Another approach is:
me@computer:~$ cat test.sh
#!/bin/bash
echo $HOSTNAME
me@computer:~$ cat test.sh | docker run -i --rm ubuntu:20.04 bash
62ba950a60fe
In this case, cat
is "pushing" the contents of the script to bash
the container, so it's functionally equivalent to my first example. The first method is "cleaner", however if you've got a more complex script, multi-line variables or other stuff that's difficult to put into a single command, then the second method is a better choice.
Note: The hostname is different in each example, because I'm using the --rm
option which discards the container once it exits. This is great when you want to run a command in a container but don't need to keep the container afterwards.
Upvotes: 0
Reputation: 2488
Expanding on the eval
approach, here is a simple bash script that will use eval to evaluate a string as a sequence of bash commands:
#!/usr/bin/env bash
echo program args: $@
eval $@
but beware, eval
comes with dangers:
https://medium.com/dot-debug/the-perils-of-bash-eval-cc5f9e309cae
Upvotes: 2
Reputation: 59906
First thing, $@
it will just print the number of argument
#!/bin/sh
echo "Value of MY_VAR is" $MY_VAR
echo "Begin"
$@
echo "Done"
$@ = stores all the arguments in a list of string
$* = stores all the arguments as a single string
$# = stores the number of arguments
What does $@ mean in a shell script?
Second thing, When run the below command
docker run env-test:latest 'echo $MY_VAR'
It will look for $MY_VAR in host system not in the container.
To access container env you have to pass them as -e MY_VAR=test
,not as argument to docker run command which will in the ENV in host.
docker run -e MY_VAR=test env-test:latest
So the value of MY_VAR
will be test
not production
.
To debug the argument to docker run
export MY_VAR2="value_from_host"
Now run
docker run env-test:latest "echo $MY_VAR2"
so the value will value_from_host
because thes argument pick from host.
Upvotes: 1