GitLab CI: Bash if Statement in Job wrong result - bash

I have a GitLab job with a bash if statement that looks like this
script:
- echo $NEW_VERSION
- export STAGE=staging
- |-
if [[ $(expr match "$NEW_VERSION", '([0-9]+)\.([0-9]+)\.([0-9]+)$') != 0 ]]; then
export STAGE=production;
fi
- echo $STAGE
The variable $NEW_VERSION comes from a previous step. The content of this variable is a semantic version string like 1.0.0 or 1.0.1-develop.1. If this variable is a prerelease (it contains the develop suffix) I want to set the $STAGE to staging otherwise to production.
My problem is that no matter which content the $NEW_VERSION variable has, $STAGE is always set to staging.
If I execute the script on my local mac the value is set right.
Here the log output:
$ echo $NEW_VERSION
11.0.0
$ export STAGE=staging
$ if [[ $(expr match "$NEW_VERSION", '([0-9]+)\.([0-9]+)\.([0-9]+)$') != 0 ]]; then # collapsed multi-line command
staging
Has anyone experienced a similar problem or has an idea why this solution dosen't work?

It's simpler to use grep.
if printf "%s\n" "$NEW_VERSION" | grep -xq '[0-9]\+\.[0-9]\+\.[0-9]\+'; then

It seems to be caused by a wrong syntax in the regular expression and the extra comma after "$NEW_VERSION" (which is appended to the value of the variable). This version works as expected.
echo $NEW_VERSION
export STAGE=staging
if [ "$(expr match "$NEW_VERSION" '^[0-9]\+\.[0-9]\+\.[0-9]\+$')" != 0 ]; then
export STAGE=production
fi
echo $STAGE

I prefer the pure bash version with =~ operator.
Verify that you are really use bash if does'nt work.
echo $NEW_VERSION
export STAGE=staging
if [[ "${NEW_VERSION}" =~ ([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
export STAGE=production
fi
echo $STAGE
Remarks:
Use double brackets with =~ operator
Do not put regular expression in quotes
Bonus:
=~ is an internal operator, so it's faster than a expr call
(tested with GNU bash, version 5.0.17)

Related

How to reassign a variable (zsh) when using source utility

The code below tests if the character from a string is matching regex or not.
str=")Y"
c="${str:0:1}"
if [[ $c =~ [A-Za-z0-9_] ]]; then
echo "YES"
output=$c
else
echo "NO"
output="-"
fi
echo $output
I am running it with
source script-name.sh
However, instead of expected printout
NO
-
I am getting an empty line without dash
NO
I understand the issue is somehow around the way i (re-)assign output variable which being me to questions
How to do it properly?
Why source utility has such implication?
UPD_1: it is for Mac's zsh, not bash
UPD_2: the issue occurs only when running script via 'source' utility like "source script-name.sh"
Running with "./script-name.sh" yield correct result as well.
Your problem can be simplified to do on the zsh command line a
echo -
which also doesn't output anything. Similarily, a
echo - x
would output simply x and not - x.
This does not depend on whether or not you are on the Mac. If you would do a
echo - -
or a
=echo -
(the latter using the external program echo) would print a dash.
Therefore, you can change in your script-name.sh a
=echo $output
or a
echo - $output
and you should be fine.
The zshbuiltins man-page explains it, when describing the echo command:
the first dash, possibly following options, is not printed, but everything following it is printed as an argument.
Therefore, in zsh, at least when printing a variable, it is better to also use a lone dash for the safe side.
Your code gives the expected output for bash 4.2.46 on RHEL7.
Are you maybe using zsh?
See echo 'the character - (dash) in the unix command line
EDIT: Ok, if it's zsh, you probably have to use a hack:
if [[ ${output} == '-' ]]; then
echo - ${output}
else
echo ${output}
fi
or use printf:
printf $output"\n"

Syntax error =~ operator in msysgit bash

I'm trying to add a function to my bash_profile for msysgit:
function git-unpushed {
brinfo=$(git branch -v | grep git-branch-name)
if [[ $brinfo =~ ("[ahead "([[:digit:]]*)]) ]]
then
echo "(${BASH_REMATCH[2]})"
fi
}
But I get the following error:
bash: conditional binary operator expected`
bash: syntax error near =~'
From what I can find, the "equals tilde" operator (=~) evaluates as regex in bash.
Why is =~ is throwing an error?
UPDATE: Here's a screenshot of inputting it manually (this is running sh.exe):
I had the same error on Bash 3.1.0 from Git installation on Windows. Ultimately I changed it to:
if echo $var | grep -E 'regexp' > /dev/null
then
...
fi
According to https://groups.google.com/forum/#!topic/msysgit/yPh85MPDyfE this is because msys doesn't ship libregex along with bash. Supposedly if you compile/find an msys built libregex, and put it in the library path, =~ starts working fine.
Update 2015: msysgit is now obsolete.
You should use the bash which comes with git-for-windows.
As mentioned in this answer, it uses a much more recent bash (4.3+), for which the =~ syntax will work.
Original answer (march 2013)
The bash packaged with msysgit might simply be too old to fully support this operator.
It is certainly too old to compare with unquoted regex, as mentioned in "Bash, version 3" and "How do I use regular expressions in bash scripts?":
As of version 3.2 of Bash, expression to match no longer quoted.
Actually, mklement0 mentions in the comments:
=~ was introduced in bash 3.0 and always supported an unquoted token on the RHS.
Up to 3.1.x, quoted tokens were treated the same as unquoted tokens: both were interpreted as regexes.
What changed in 3.2 was that quoted tokens (or quoted substrings of a token) are now treated as literals.
But I tried with quotes (in the latest msysgit 1.8.1.2), and it still fails:
vonc#voncvb /
$ /bin/bash --version
GNU bash, version 3.1.0(1)-release (i686-pc-msys)
Copyright (C) 2005 Free Software Foundation, Inc.
vonc#voncvb /
$ variable="This is a fine mess."
vonc#voncvb /
$ echo "$variable"
This is a fine mess.
vonc#voncvb /
$ if [[ "$variable" =~ T.........fin*es* ]] ; then echo "ok" ; fi
bash: conditional binary operator expected
bash: syntax error near `=~'
vonc#voncvb /
$ if [[ "$variable" =~ "T.........fin*es*" ]] ; then echo "ok" ; fi
bash: conditional binary operator expected
bash: syntax error near `=~'
vonc#voncvb /
Here is a solution that supports extracting matched strings. If the operator =~ is not supported by bash, then the sed command is used (installed with msysgit)
if eval "[[ a =~ a ]]" 2>/dev/null; then
regexMatch() { # (string, regex)
eval "[[ \$1 =~ \$2 ]]"
return $?
}
elif command -v /bin/sed >/dev/null 2>&1; then
regexMatch() { # (string, regex)
local string=$1
if [[ ${2: -1} = $ ]]; then
local regex="(${2%$})()()()()()()()()$"
else
local regex="($2)()()()()()()()().*"
fi
regex=${regex//\//\\/}
local replacement="\1\n\2\n\3\n\4\n\5\n\6\n\7\n\8\n\9\n"
local OLD_IFS=$IFS
IFS=$'\n'
BASH_REMATCH=($(echo "$string" | /bin/sed -rn "s/$regex/$replacement/p" | while read -r; do echo "${REPLY}"; done))
IFS=$OLD_IFS
[[ $BASH_REMATCH ]] && return 0 || return 1
}
else
error "your Bash shell does not support regular expressions"
fi
Usage example:
if regexMatch "username#host.domain" "(.+)#(.+)"; then
echo ${BASH_REMATCH[0]}
echo ${BASH_REMATCH[1]}
echo ${BASH_REMATCH[2]}
fi

How do I test if a string starts with another in bash?

Very similar but not duplicate : https://stackoverflow.com/a/2172367/57883
I'm in Git Bash 3.1 (at least that's what comes up in the prompt when I type bash inside git bash.
and $ test [["DEV-0" == D*]] || echo 'fail' prints fail.
if [['DEV-0-1' == DEV* ]]; then echo "yes"; says [[DEV-0-1: command not found
I'm trying to test if git branch returns something that starts with DEV. but I can't seem to apply the answer. is it because all my attempts are using a string literal on the left instead of a variable value?
I've also tried it on ideone http://ideone.com/3IyEND
and no luck.
It's been ~14 years since I was good with a linux prompt.
What am I missing for a string starts with test in bash?
You missed a space there:
if [[ 'DEV-0-1' == DEV* ]]; then echo "yes"; fi
^^
I'd probably rather do the check like this:
s1=DEV-0-1
s2=DEV
if [ "${s1:0:${#s2}}" == "$s2" ]; then
echo "yes"
fi

Bash Scripting: greping the parameter

Here is my problem. I have script and I want to make sure that the parameter that is entered when the script is called matches a variable name inside the script.
For example:
./valid foo <- being the script call
#!/bin/bash
PARAM=$1
VAR=/foo/
if grep -c $PARAM == $VAR
then
echo yes
fi
echo no
I am having the worst time using grep, I'm not sure how to use it properly inside of a script and after scouring the internet I think I need some specific feedback on my problem.
Thanks,
EA
This is not robust, but you can do:
if echo "$VAR" | grep -q "$PARAM"; then
It is probably better to simply do:
if test "$VAR" = "$PARAM"; then
If you are trying to match a regex, bash allows:
if [[ "$VAR" =~ "$PARAM" ]]; then
to match the fixed string $VAR against the regex $PARAM. If $VAR is the regex, you should reverse the order of the arguments. (That is, [[ "$PARAM" =~ "$VAR ]].)
You could search inside your script, since the declaration is the name followed by an equal sign:
if egrep "^\s*$PARAM=" $0
then
echo yes
else
echo no
fi
to list variables use
set -o posix ; set
the posix thingie prevents listing of functions.
In order to isolate parameters local to script, run it from the shell and store the result,
then run it from your script and compare output
(set -o posix ; set) >/tmp/variables.before
(set -o posix ; set) >/tmp/variables.after

shell script working fine on one server but not on another

the following script is working fine on one server but on the other it gives an error
#!/bin/bash
processLine(){
line="$#" # get the complete first line which is the complete script path
name_of_file=$(basename "$line" ".php") # seperate from the path the name of file excluding extension
ps aux | grep -v grep | grep -q "$line" || ( nohup php -f "$line" > /var/log/iphorex/$name_of_file.log & )
}
FILE=""
if [ "$1" == "" ]; then
FILE="/var/www/iphorex/live/infi_script.txt"
else
FILE="$1"
# make sure file exist and readable
if [ ! -f $FILE ]; then
echo "$FILE : does not exists. Script will terminate now."
exit 1
elif [ ! -r $FILE ]; then
echo "$FILE: can not be read. Script will terminate now."
exit 2
fi
fi
# read $FILE using the file descriptors
# $ifs is a shell variable. Varies from version to version. known as internal file seperator.
# Set loop separator to end of line
BACKUPIFS=$IFS
#use a temp. variable such that $ifs can be restored later.
IFS=$(echo -en "\n")
exec 3<&0
exec 0<"$FILE"
while read -r line
do
# use $line variable to process line in processLine() function
processLine $line
done
exec 0<&3
# restore $IFS which was used to determine what the field separators are
IFS=$BAKCUPIFS
exit 0
i am just trying to read a file containing path of various scripts and then checking whether those scripts are already running and if not running them. The file /var/www/iphorex/live/infi_script.txt is definitely present. I get the following error on my amazon server-
[: 24: unexpected operator
infinity.sh: 32: cannot open : No such file
Thanks for your helps in advance.
You should just initialize file with
FILE=${1:-/var/www/iphorex/live/infi_script.txt}
and then skip the existence check. If the file
does not exist or is not readable, the exec 0< will
fail with a reasonable error message (there's no point
in you trying to guess what the error message will be,
just let the shell report the error.)
I think the problem is that the shell on the failing server
does not like "==" in the equality test. (Many implementations
of test only accept one '=', but I thought even older bash
had a builtin that accepted two '==' so I might be way off base.)
I would simply eliminate your lines from FILE="" down to
the end of the existence check and replace them with the
assignment above, letting the shell's standard default
mechanism work for you.
Note that if you do eliminate the existence check, you'll want
to either add
set -e
near the top of the script, or add a check on the exec:
exec 0<"$FILE" || exit 1
so that the script does not continue if the file is not usable.
For bash (and ksh and others), you want [[ "$x" == "$y" ]] with double brackets. That uses the built-in expression handling. A single bracket calls out to the test executable which is probably barfing on the ==.
Also, you can use [[ -z "$x" ]] to test for zero-length strings, instead of comparing to the empty string. See "CONDITIONAL EXPRESSIONS" in your bash manual.

Resources