Parameter expansion to assign environment variable in bash - 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

Related

How to split a string by underscore and extract an element as a variable in bash?

Suppose I have a string such like s=DNA128533_mutect2_filtered.vcf.gz. How could I extract the DNA128533 as an ID variable.
I tried
id=(cut -d_ -f1 <<< ${s}
echo $id
It seems not working. some suggestions? Thanks
No need to spend a sub-shell calling cut -d'_' -f1 and using bashism <<< "$s".
The POSIX shell grammar has built-in provision for stripping-out the trailing elements with variable expansion, without forking a costly sub-shell or using non-standard Bash specific <<<"here string".
#!/usr/bin/env sh
s=DNA128533_mutect2_filtered.vcf.gz
id=${s%%_*}
echo "$id"
You want to filter the DNA... part out of the filename. Therefore:
s="DNA128533_mutect2_filtered.vcf.gz"
id=$(echo "$s" | cut -d'_' -f1)
echo "$id"
If you want to use your way of doing it (with <<<), do this:
id=$(cut -d'_' -f1 <<< "$s")
echo "$id"
Your command has some syntax issues, like you are missing ).
And you want the output of the command to be stored in variable id, so you have to make it run via the $( ) syntax.
IFS is the bash way delimiter, we can cut string as below:
IFS='_' read -r -a array <<< "a_b_c_d"
echo "${array[0]}"

Default value with shell expressions in Dockerfile ARG and ENV

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

What's wrong with this bash script using cut and sed (cut: command not found)?

I'm getting server and path from an NFS location in bash as follows:
#!/bin/bash
ST="/net/10.111.111.111/path/to/some/dir"
echo $ST
SERVER=$(echo $ST | cut -d'/' -f3)
echo $SERVER
PATH=$(echo $ST | cut -d'/' -f4-)
echo $PATH
PATH=$(echo $ST | cut -d'/' -f4-)
echo $PATH
The same 2 lines are repeated above on purpose. The output is:
/net/10.111.111.111/path/to/some/dir
10.111.111.111
path/to/some/dir
./nn.sh: line 9: cut: command not found
I'm getting what I want but I don't understand why the second call to PATH= produces the above error. What am I missing?
PATH is a system variable which the bash shell uses to find where
your binaries(eg cut) are.
So, till :
PATH=$(echo $ST | cut -d'/' -f4-)
things work as expected. But after the command substitution ie $(...), PATH points to a non-standard directory where bash could not find the standard binaries.
So the subsequent command :
PATH=$(echo $ST | cut -d'/' -f4-)
gave you the error :
./nn.sh: line 9: cut: command not found
Moral
Never use uppercase variables for your scripts as they are reserved for the system.

awk shell variables not working

Hi I'm using GNU awk version 3.1.5 and I've specified 2 variables in a KSH script
PKNAME= ls -lt /var/db/pkg | tr -s " " | cut -d" " -f9
PKDATE= ls -lt /var/db/pkg/$PKNAME/ | tr -s " " | cut -d" " -f6-8
I'm trying to prove that I'm getting the correct output, by running a test using
echo bar
awk -F, -v pkname="$PKNAME" -v pkdate="$PKDATE" 'BEGIN{print pkname, pkdate, "foo"; exit}'
echo baz
The output from this results in 2 blank spaces and foo, like so
bar
foo
baz
I have tried, double quoting the variables, single quotes and back ticks. Also tried double quotes with back ticks.
Any ideas why the variables are not being executed? I'm fairly new to awk and appreciate any help! Thanks
I suppose it is possible that it is not possible to run a sub shell comand within an awk statement. Is this true?
This has nothing to do with awk. The problem is in the way you're assigning your variables. Your lines should be like this:
PKNAME=$(ls -lt /var/db/pkg | tr -s " " | cut -d" " -f9)
There can be no spaces around either side of an assignment in the shell.
At the moment, you're running the command ls -lt ... with a variable PKNAME temporarily assigned to an empty string. In subsequent commands the variable remains unset.
Your awk command should remain unchanged, i.e. the shell variables should be passed like -v pkname="$PKNAME". As an aside, it's generally considered bad practice to use uppercase variable names, as these should be reserved for internal use by the shell.

Passing Bourne Shell variable into cut command

I am trying to do the following.
foo="foo:foo1"
cc= `$foo | cut -f2 -d:`
I understand why this would not work but I am at a loss as to do this.
Thanks in advance.
Try this:
foo="foo:foo1"
cc=`echo $foo | cut -f2 -d:`
There are 2 changes to make:
You need to echo the value of shell
variable foo and then cut it.
You must not have white spaces around =
when assigning a value to a shell
variable.
in bourne, you can use set. No external command needed.
$ foo="foo:foo1"
$ IFS=":"
$ set -- $foo
$ echo $2
foo1

Resources