Bash - Single Quotes Being Added to Spaces [duplicate] - bash

This question already has answers here:
Reading quoted/escaped arguments correctly from a string
(4 answers)
Bash doesn't parse quotes when converting a string to arguments
(5 answers)
Bash inserting extra, incorrect single quotes when quoting argument list
(2 answers)
Closed 3 years ago.
I have the following:
test.ini
BUILD_ARGS='--build-arg user="test user" --build-arg pass=testPass'
test.sh
#!/bin/bash
set -x
source test.ini
docker build -t test:test ${BUILD_ARGS} .
Output of test.sh
+ source test.ini
++ BUILD_ARGS='--build-arg smb_user="test user" --build-arg smb_pass=testPass '
+ docker build -t test:test --build-arg 'user="test' 'user"' --build-arg pass=testPass .
Why are extra single quotes being added in between "test" and "user"? I would expect the command to be executed as:
docker build -t test:test --build-arg user="test user" --build-arg pass=testPass .

Arguments needs to be constructed as an array:
BUILD_ARGS=(--build-arg user="test user" --build-arg pass="testPass")
docker build -t test:test "${BUILD_ARGS[#]}"

Related

Can't Escape $ (Dollar Sign) in Environment Variable in Dockerfile

I am trying to put a password in a command in a Dockerfile. The problem is it has a $ in it, so the variable get evaluated but the $ is in the value so it tries to evaluate that afterwards.
The Dockerfile is called from a bash script, so to get the password into the file I did something like:
read -p "Input Username:" Username
read -s -p "Input Password:" Password
docker build --build-arg Username=$Username --build-arg Password=$Password...
And in the Dockerfile I have:
ARG Username
ARG Password
Then within the Dockerfile, I have tried this:
curl -u "$Username:$Password"
It gets expanded to something like
curl -u "Username:Pass12$34"
Which doesn't work as it tries to evaluate $34 as a variable. I tried using single quotes but that didn't evaluate the variable at all. Any help is appreciated.

Function that uses all arguments in bash? [duplicate]

This question already has answers here:
Propagate all arguments in a Bash shell script
(12 answers)
Closed 2 years ago.
I'm trying to use all arguments from my function like this
function docker_run {
docker run \
-it --rm \
--entrypoint "" \
--volume "$(pwd):/${repo}" \
--workdir "/${repo}" \
alpine/git:v2.26.2 \
"$*"
}
docker_run sh -c "git reset && git add --a && git status"
this gives the error:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: "sh -c git reset && git add --a && git status": executable file not found in $PATH": unknown.
if I remove quotes around $* the error is:
usage: git [--version] [--help] [-C ]...
is *$ the correct variable to use? ideally I'd want docker_run to work with any possible argument combination
If you want to use all arguments, you should use $# and not $*. $# is special in that it's array-like, so when you put it in quotes it expands to all arguments. $* is a string that joins the arguments with spaces, so it globs into one argument.

Pass ENV to Docker container running single command

This prints blank:
docker run --rm --env HELLO="world" ubuntu:18.04 bash -c "echo $HELLO"
However this works:
docker run --rm -it --env HELLO="world" ubuntu:18.04 bash
# in the container
echo $HELLO
HELLO seems passed to the container though:
docker run --rm --env HELLO="world" ubuntu:18.04 env
Why is the first command not seeing HELLO? What am I missing?
Because of the double quotes, $HELLO will be evaluated by the docker host itself once the command got executed before going inside the container. So you need to either escape the dollar sign ($) using Backslash (\) which tells the bash that the $ is a part of the command itself and no need to be evaluated by the current shell (which is the docker host in our case) or use single quotes ('') like this:
Using single quotes
$ docker run --rm --env HELLO="world" ubuntu:18.04 bash -c 'echo $HELLO'
world
Using Backslash to escape
$ docker run --rm --env HELLO="world" ubuntu:18.04 bash -c "echo \$HELLO"
world
The reason you are not seeing what you expect is because things are being evaluated before you expect them to be evaluated.
When you run:
docker run --rm --env HELLO="world" ubuntu:18.04 bash -c "echo $HELLO"
The "echo $HELLO" really isn't any different to bash than:
echo "echo $HELLO"
The shell (bash) parses double quotes (") and things inside them. It sees "echo $HELLO" and replaces the variable $HOME with it's value. If $HOME is not defined, this evaluates to echo.
So,
echo "echo $HELLO"
is parsed and evaluted by your shell. Which then just runs this at the end:
echo "echo "
So the "echo $HELLO" in your docker command is evaluated to "echo " and that's what gets passed to the docker command.
What you want to do is to prevent your shell from evaluating the variable. You can do it a couple of ways:
You can use single quotes instead of double quotes. Your shell doesn't parse it; it will be passed to the bash inside the container as is:
docker run --rm --env HELLO="world" ubuntu:18.04 bash -c 'echo $HELLO'
You can escape the $ to avoid evaluating it in this shell and let the bash inside the docker container evaluate it:
docker run --rm --env HELLO="world" ubuntu:18.04 bash -c "echo \$HELLO"

Silence docker rm command in bash [duplicate]

This question already has answers here:
How can I suppress all output from a command using Bash?
(8 answers)
Closed 3 years ago.
I tried docker container rm container-name > /dev/null but this still prints Error: No such container: container-name. I'm trying to silence this error in my bash script.
Send stderr to /dev/null:
docker container rm container-name 2> /dev/null

How to pass arguments with space by environment variable?

On bash shell, I want to pass argument by environment variable.
like this...
$ export DOCKER_OPTIONS="-p 9200:9200 -e ES_JAVA_OPTS='-Xmx1g -Xms1g' -d "
$ docker run -d $DOCKER_OPTIONS elasticsearch
I expect that "ES_JAVA_OPTS='-Xmx1g -Xms1g'" is passed as an option value of "-e". But I couldn't find a way.
$ set -x
$ docker run -d $DOCKER_OPTIONS elasticsearch
+ docker run -d -p 9200:9200 -e 'ES_JAVA_OPTS='\''-Xmx1g' '-Xms1g'\''' elasticsearch
unknown shorthand flag: 'X' in -Xms1g'
This separated -Xms1g as an another option.
$ docker run -d "$DOCKER_OPTIONS" elasticsearch
+ docker run -d '-p 9200:9200 -e ES_JAVA_OPTS='\''-Xmx1g -Xms1g'\''' elasticsearch
docker: Invalid containerPort: 9200 -e ES_JAVA_OPTS='-Xmx1g -Xms1g'.
This bundled the parameters together.
What should I do?
Use an array to circumvent these awkward parsing problems. Arrays are great because you don't need to do any special quote when defining them. The only place you have to be careful with quotes is when expanding them: always put quotes around "${array[#]}".
dockerOptions=(-p 9200:9200 -e ES_JAVA_OPTS='-Xmx1g -Xms1g' -d)
docker run -d "${dockerOptions[#]}" elasticsearch
Note that export isn't needed since you're passing the options to docker via its command-line rather than as an environment variable.
Also, all uppercase names are reserved for the shell. It's best to avoid them when defining your own variables.

Resources