Default value with shell expressions in Dockerfile ARG and ENV - shell

I'd like to receive the version number as a single argument and extract major/minor numbers for various places in URLs at the RUN scripts in a Dockerfile.
ARG CUDA_VERSION
ARG CUDNN_VERSION
ENV CUDA_FULL="${CUDA_VERSION:-8.0.61_375.26}" \
CUDA_MAJOR="$(echo ${CUDA_VERSION:-8.0.61_375.26} | cut -d. -f1)" \
CUDA_MINOR="$(echo ${CUDA_VERSION:-8.0.61_375.26} | cut -d. -f2)" \
CUDA_MAJMIN="$CUDA_MAJOR.$CUDA_MINOR"
ENV CUDNN_FULL="${CUDNN_VERSION:-7.0.1}" \
CUDNN_MAJOR="$(echo ${CUDNN_VERSION:-7.0.1} | cut -d. -f1)" \
CUDNN_MINOR="$(echo ${CUDNN_VERSION:-7.0.1} | cut -d. -f2)" \
CUDNN_MAJMIN="$CUDNN_MAJOR.$CUDNN_MINOR"
RUN curl -LO https://.../${CUDNN_FULL}/.../...${CUDA_MAJMIN}...
If I try the above, the shell expressions are not evaluated and just pasted as-is in the later RUN scripts.
Would be there better way to achieve this, without creating an external shell scripts that wraps this Dockerfile?

From the documentation:
The ${variable_name} syntax also supports a few of the standard bash modifiers as specified below:
${variable:-word} indicates that if variable is set then the result will be that value. If variable is not set then word will be the result.
${variable:+word} indicates that if variable is set then word will be the result, otherwise the result is the empty string.
ENV is special docker build command and doesn't support this. What you are looking for is to run Shell commands in ENV. So this won't work.
Possible solution is to use a bash script
cuda_version.sh
#!/bin/bash
CUDA_FULL="${CUDA_VERSION:-8.0.61_375.26}"
CUDA_MAJOR="$(echo ${CUDA_VERSION:-8.0.61_375.26} | cut -d. -f1)"
CUDA_MINOR="$(echo ${CUDA_VERSION:-8.0.61_375.26} | cut -d. -f2)"
CUDA_MAJMIN="$CUDA_MAJOR.$CUDA_MINOR"
CUDNN_FULL="${CUDNN_VERSION:-7.0.1}"
CUDNN_MAJOR="$(echo ${CUDNN_VERSION:-7.0.1} | cut -d. -f1)"
CUDNN_MINOR="$(echo ${CUDNN_VERSION:-7.0.1} | cut -d. -f2)"
CUDNN_MAJMIN="$CUDNN_MAJOR.$CUDNN_MINOR"
And change your dockerfile to
ARG CUDA_VERSION=8.0.61_375.26
ARG CUDNN_VERSION=7.0.1
ENV CUDA_VERSION=${CUDA_VERSION} CUDNN_VERSION=${CUDNN_VERSION}
COPY cuda_version.sh /cuda_version.sh
RUN bash -c "source /cuda_version.sh && curl -LO https://.../${CUDNN_FULL}/.../...${CUDA_MAJMIN}..."
You can remove the default values from your shell file as they will always be there from the Dockerfile arguments/environment

Related

How to assign values in bash after running commands

NAME=aaa/bbbbb:0.1.2
How can I assign the new string?
NEW_VAR=$NAME | sed 's/.*\///' | cut -f1 -d":"
Assuming you are using bash, you don't actually need to shell out to other commands, there is built in string mangling functions:
NEW_VAR=${NAME%%:*}
If you would prefer to, it'll be something like this:
NEW_VAR=$(echo -n $NAME | cut -f1 -d":")

"not found" error in shell script

I am trying to write a script that should take values from a xml file.
Here is the xml file :-
`<manifestFile>
<productInformation>
<publicationInfo>
<pubID pcsi-selector="P.S.">PACODE</pubID>
<pubNumber/>
</publicationInfo>
</productInformation>
</manifestFile>`
and i my code is
:-
#!/bin/sh
Manifest=""
Manifest= `/bin/grep 'pcsi-selector="' /LDCManifest.xml | cut -f 2 -d '"'`
echo $Manifest
I expect my result to be P.S. , but it keeps throwing error as :-
./abc.sh: P.S.: not found
I am new to shell and i am not able to figure out whats the error here ?
You can't have a space after the =.
When you run this command:
Manifest= `/bin/grep 'pcsi-selector="' /LDCManifest.xml | cut -f 2 -d '"'`
It's the same as this:
Manifest='' `/bin/grep 'pcsi-selector="' /LDCManifest.xml | cut -f 2 -d '"'`
That tells the shell to
Run the grep command.
Take its output
Run that output as a command, with the environment variable Manifest set to the empty string for the duration of the command.
Get rid of the space after the = and you'll get the result you want.
However, you should also avoid using backticks for command substitution, because they interfere with quoting. Use $(...) instead:
Manifest=$(grep 'pcsi-selector="' /LDCManifest.xml | cut -f2 -d'"')
Also, using text/regex-based tools like grep and cut to manipulate XML is clunky and error-prone. You'd be better off installing something like XMLStarlet:
Manifest=$(xmlstarlet sel -t \
-v '/manifestFile/productInformation/publicationInfo/pubID/#pcsiselector' -n \
/LDCManifest.xml)
Or simpler:
grep -oP 'pcsi-selector="\K[^"]+' /LDCManifest.xml
would print
P.S.
assign
Manifest=$(grep -oP 'pcsi-selector="\K[^"]+' /LDCManifest.xml)

tilde based exec from a variable

This sure is something simple but I can't seem to figure out. Any idea what's wrong when I exec the same command via a variable?
this works:
$ echo `git --version | cut -d' ' -f3`
1.8.4
but this doesn't:
$ c="git --version | cut -d' ' -f3"
$ echo `$c`
git version 1.8.4
Any ideas?
Your code:
c="git --version | cut -d' ' -f3"
echo `$c`
Is the equivalent of:
git --version "|" cut -d' ' -f3
Since the pipe character is inside a variable, it will not get evaluated as a shell metacharacter, and its the same effect as if you typed it on the command line with quotes or backslash to escape it. This is easier to see if you use this instead:
c="echo a b c | wc -w"
echo `$c`
As already posted, the answer is to use "eval" so the shell expands the variable and then tries to execute it as shell source, then metacharacters like the pipe will be recognized.
I don't have the exact reason at my fingertips, but ... you can't do that.
Pipes and redirections seem to be especially special.
However, eval will do the job:
$ c="git --version | cut -d' ' -f3"
$ eval "$c"
1.7.5.4

Parameter expansion to assign environment variable in bash

I want to get the current svn revision using bash and set it as the environment variable SVN_REVISION. This environment variable may or may not be already set. If it's already set then I echo that, if not set then I compute it and then echo it. I DONT'T want to override if SVN_REVISION is already set. I am using the following script which is failing owing to my lack of understanding of parameter expansion.
#!/bin/bash
# If no directory provided as an argument, uses the current working directory as the source directory.
RAW_SRC_DIR=${1:-`pwd`}
COMPUTE_REVISION=$(svn info ${RAW_SRC_DIR} | grep '^Revision' | cut -d ':' -f2 | tr -d ' ')
echo "${COMPUTE_REVISION}" ##Gets the revision successfully
${SVN_REVISION:="$COMPUTE_REVISION"} #Fails with message: <SVN_REVISION> command not found
export SVN_REVISION
echo $SVN_REVISION
How do I fix it?
One of the effects of the ${parameter:=word} syntax is that the value of parameter is substituted. That means your shell is going to try to execute whatever number you get as a command. Just do the assignment in the echo line and put the export afterwards.
echo ${SVN_REVISION:="$COMPUTE_REVISION"}
export SVN_REVISION
Why not just do it the obvious way?
[[ -z $SVN_REVISION ]] && \
SVN_REVISION=$(svn info ${1:-`pwd`} | grep '^Revision' | cut -d ':' -f2 | tr -d ' ')
echo $SVN_REVISION
export SVN_REVISION
or, if you insist
echo ${SVN_REVISION:=$(svn info ${1:-`pwd`} |
grep '^Revision' |
cut -d ':' -f2 |
tr -d ' ')}
export SVN_REVISION

makefile shell grep doesn't find the file I tried to specify

This approach is not finding the file I think I specified.
SHELL = /bin/bash
PKG_NAME = test
PKG_VERSION := $(shell grep -i '^version' $(PKG_NAME)/DESCRIPTION | cut -d ':' -f2 | cut -d ' ' -f2)
In the shell itself, grep -i '^version' test/DESCRIPTION | cut -d ':' -f2 | cut -d ' ' -f2 does return the version successfully, e.g. 0.4-7
But, running via the makefile returns:
grep: test: Is a directory
grep: /DESCRIPTION: No such file or directory
test is a directory, that's true, but test/DESCRIPTION does exist, so I'm guessing $(PKG_NAME)/DESCRIPTION wasn't the right way to assemble the file name.
Suggestions? Thanks.
That error indicates that grep is seeing test and /DESCRIPTION as two separate arguments. Do you have extra spaces on the PKG_NAME assignment line or an errant space between $(PKG_NAME) and /DESCRIPTION in the $(shell ...) line?
As a general rule you might want to start putting quotes around arguments to shell commands (i.e. '$(PKG_NAME)/DESCRIPTION') to prevent this sort of word splitting issue (though without spaces you generally don't have that sort of problem).

Resources