Use Dockerfile commands inside of a shell script? - bash

Suppose that I have an entry-point to a shell script as I want to use some conditionals in a dockerfile. Is there a way to do something like this?
ENTRYPOINT ["./entry.sh", "lambda-name"]
Inside of entry.sh
#!/usr/bin/env bash
lambda_name=$1
echo "$lambda_name"
if [ "$lambda_name" = "a.handler" ]; then
CMD [ "a.handler" ]
elif [ "$lambda_name" = "b.handler" ];then
CMD [ "b.handler" ]
else
echo "not found"
fi

first of all you don't need that complication.
why not like this?
#!/usr/bin/env bash
lambda_name=$1
echo "$lambda_name"
if [ "$lambda_name" = "a.handler" ]; then
./a.handler
elif [ "$lambda_name" = "b.handler" ];then
./b.handler
else
echo "not found"
fi
also in your script you could use something like
exec "$#"
at the end of your script. this would run all your arguments.

The ENTRYPOINT is the main container process. It executes when you docker run the built image; it's too late to run any other Dockerfile directives at that point.
In particular, the ENTRYPOINT gets passed the image's CMD (or a Compose command: or an alternate command after the docker run image-name) as arguments, and it can do whatever it wants with that. So at this point you don't really need to "set the container's command", you can just execute whatever command it is you might have wanted to run.
#!/bin/sh
case "$1" in
a.handler) a.handler ;;
b.handler) b.handler ;;
*)
echo "$1 not found" >&2
exit 1
;;
esac
With this setup, a fairly common Docker pattern is just to take whatever gets passed as arguments and to run that at the end of the entrypoint script.
#!/bin/sh
# ... do any startup-time setup required here ...
exec "$#"
That matches what you show in the question: if the first argument is a.handler then run that command, and so on.

Related

Environment Variables inside the container, but not used in the bash script

I have an application that runs inside a docker container. First I build the image and then run the container. My run command is:
docker run --rm -it -e MODE=custom -e Station=RT -e StartDateReport=2022-09-10 -e Period=1 my-image:1.0.0
I declare the variables MODE, Station, StartDateReport and Period as environment variables. When I start a terminal from the container and type echo $MODE I will get the correct value, custom.
So far, so good, but I am interested in using these variables in a bash script. For example in start.sh I have the following code:
#!/bin/bash
if [[ $MODE == custom ]]; then
// do sth
fi
and here inside the script my variable MODE is undefined, and hence I obtain wrong results.
EDIT
As discussed in the comments below, my application if based on a cronjob to start running.
I managed to solve by myself the problem and the answer is in the comments.
In your environment, does your variable definition have the form
export MODE="custom"
Modified version of your script:
#!/bin/bash
test -z "${MODE}" && ( echo -e "\n\t MODE was not exported from calling environment.\n" ; exit 1 )
if [[ $MODE == custom ]]
then
#// do sth
echo "do sth"
fi
I found the solution for this problem, so I will post the answer here to help others that have the same problem. I found the solution here: How to load Docker environment variables in container
I included export xargs --null --max-args=1 echo < /proc/1/environ in start.sh
Thus, start.sh will be:
#!/bin/bash
export xargs --null --max-args=1 echo < /proc/1/environ
if [[ $MODE == custom ]]; then
// do sth
fi

script file not found when using source

I have a bash script in a file named reach.sh.
This file is given exe rights using chmod 755 /Users/vb/Documents/util/bash/reach.sh.
I then created an alias using alias reach='/Users/vb/Documents/util/bash/reach.sh'
So far this works great.
It happens that I need to run this script in my current process, so theoretically I would need to add . or source before my script path.
So I now have alias reach='source /Users/vb/Documents/util/bash/reach.sh'
At this point when I run my alias reach, the script is failing.
Error /Users/vb/Documents/util/bash/reach.sh:7: = not found
Line 7 if [ "$1" == "cr" ] || [ "$1" == "c" ]; then
Full script
#!/bin/bash
# env
REACH_ROOT="/Users/vb/Documents/bitbucket/fork/self"
# process
if [ "$1" == "cr" ] || [ "$1" == "c" ]; then
echo -e "Redirection to subfolder"
cd ${REACH_ROOT}/src/cr
pwd
else
echo -e "Redirection to root folder"
cd ${REACH_ROOT}
pwd
fi
Any idea what I could be missing ?
I'm running my script in zsh which is not a bash shell, so when I force it to run in my current process it runs in a zsh shell and does not recognize bash commands anymore.
In your question, you say "It happens that I need to run this script in my current process", so I'm wondering why you are using source at all. Just run the script. Observe:
bash-script.sh
#!/bin/bash
if [ "$1" == "aaa" ]; then
echo "AAA"
fi
zsh-script.sh
#!/bin/zsh
echo "try a ..."
./bash-script.sh a
echo "try aaa ..."
./bash-script.sh aaa
echo "try b ..."
./bash-script.sh b
output from ./zsh-script.sh
try a ...
try aaa ...
AAA
try b ...
If, in zsh-script.sh, I put source in front of each ./bash-script.sh, I do get the behavior you described in your question.
But, if you just need to "run this script in my current process", well, then ... just run it.
source tries to read a file as lines to be interpreted by the current shell, which is zsh as you have said. But simply running it, causes the first line (the #!/bin/bash "shebang" line) to start a new shell that interprets the lines itself. That will totally resolve the use of bash syntax from within a zsh context.

Accessing the number of arguments pass into a docker run command script

I have a docker Entrypoint script that looks like this:
#!/bin/sh
LABEL=$1
mkdir -p /backup/$LABEL
...
I can access the arguments passed in the normal bash way via $1, $2, etc. but I also need to know the number of arguments passed in. At first I thought I could do this like this:
if [ $# -eq 2 ];
then
However that does not work. Any ideas on how to retrieve the number of arguments?
TIA,
Ole
Weird. This should work. But, if you can read the positional parameters $1 and $2, you may have luck looping over them:
#!/bin/bash
params="$#"
while param=$1 && [ -n "$param" ]
do
shift
((count += 1))
echo "here comes $param"
done
echo "All params: ${params[#]}"
echo "We saw $count of them"
OK - In reality nothing passed in was resolving. The reason is that the entrypoint line needs to look like this:
ENTRYPOINT ["bash", "/run.sh"]
Mine looked like this:
ENTRYPOINT ["/run.sh"]
See here for more info:
Referencing the first argument passed to the docker entrypoint?

How to escape space in bash script from inline if?

I know that similar questions have been asked and answered before on stackoverflow (for example here and here) but so far I haven't been able to figure it out for my particular case.
I'm trying to create a script that adds the -v flag only if the variable something is equal to "true" (what I'm trying to do is to mount the current folder as a volume located at /src in the Docker container):
docker run --name image-name `if [ "${something}" == "true" ]; then echo "-v $PWD:/src"; fi` ....
The problem is that $PWD may contain spaces and if so my script won't work. I've also tried assigning "$PWD" to an intermediate variable but it still doesn't work:
temp="$PWD"
docker run --name image-name `if [ "${something}" == "true" ]; then echo "-v $temp:/src"; fi` ....
If I run:
docker run --name image-name -v "$PWD":/src ....
from plain bash (without using my script) then everything works.
Does anyone know how to solve this?
Use an array.
docker_args=()
if something; then
docker_args+=( -v "$PWD/src" )
fi
docker run --blah "${docker_args[#]}" …
Don't have arrays? Use set (in a function, so it doesn't affect outer scope).
Generally:
knacker() {
if something; then
set -- -v "$PWD:/src" "$#"
fi
crocker "$#"
}
knacker run --blah
But some commands (like docker, git, etc) need special treatment because of their two-part command structure.
slacker() {
local cmd="$1"
shift
if something; then
set -- -v "$PWD:/src" "$#"
fi
docker "$cmd" "$#"
}
slacker run --blah
Try this (using the array way):
declare -a cmd=()
cmd+=(docker run --name image-name)
if [ "${something}" = "true" ]
then
cmd+=(-v "$PWD:/src")
fi
"${cmd[#]}"

Unix while loop to test command line argument if it is a directory

Trying to make a script that will take a command line argument as a pathname and then test if it is a working directory. Then I wish to run commands (tests) on the directory such as how many files in what sub directories etc.
I am unable to think of a logic to test this with. How would you determine if the argument is a directory?
This is what I have tried
if [ -d "$1" ]
then
echo "It works"
fi
I dont get "It works" when I try this. So I switched it to -a for a file because it is easier to test. And again, I do not get the echo output.
Use the -d option to the test command.
if [ -d "$1" ]
then ...
fi
The title mentions a while loop, but none of the previous commentary seems to mention that. You might try a simple script like:
#!/bin/sh
for arg; do
if test -d "$arg";
echo "$arg is a directory"
else
echo "$arg is not a directory"
fi
done
For variety, you could rewrite that as:
#!/bin/sh
for arg; do
not=$(test -d "$arg" || echo "NOT ")
echo "$arg is ${not}a directory"
done

Resources