I am having a trouble checking if a branch exists in a Jenkins job.
My shell scripts is as follows:
set +e
BRANCH_EXISTS=$(git ls-remote --quiet | grep -w ${BRANCH_NAME})
if [[ -z $"{BRANCH_EXISTS}" ]]
then
echo "Branch does not exist"
else
echo "Branch exists"
fi
Following is a log:
07:36:26 + BRANCH_EXISTS='4cbe2d1776db4dc263a1e7884e35da49a0a6f309 refs/heads/equalizer_fe_testing'
07:36:26 + [[ -z {BRANCH_EXISTS} ]]
07:36:26 + echo 'Branch exists'
07:36:26 Branch exists
...
07:36:27 + BRANCH_NAME=test/fe-testing_staging1
07:36:27 ++ grep -w test/fe-testing_staging1
07:36:27 ++ git ls-remote --quiet
07:36:28 + BRANCH_EXISTS=
07:36:28 + [[ -z {BRANCH_EXISTS} ]]
07:36:28 + echo 'Branch exists'
07:36:28 Branch exists
07:36:29 Finished: SUCCESS
As you can see, in one case I check for a branch that does not exist. But still the if condition passes. I have tried with if [[ -n $"{BRANCH_EXISTS}" ]] as well but still gets the same result.
What am I doing wrong here?
You are incorrectly using the test operator to check if string is empty. In most shells, variable interpolation happens with ${var} and not {var} or $"{var}"
$ var=foo
$ [[ -z $var ]] && echo ok
$ [[ -z $var ]] || echo ok
ok
$ var=
$ [[ -z $var ]] && echo ok
ok
$ [[ -z var ]] && echo ok # does not assert, because literal 'var' is not empty
When you are doing [[ -z {var} ]] you are not interpolating var, but comparing against a literal string {var} which is never empty.
Change your conditional to [[ -z "${BRANCH_EXISTS}" ]] to make it work as expected.
As Inian already explained in his answer, $"{BRANCH_EXISTS}", but "${BRANCH_EXISTS}" would be correct. However, there is more to it:
In your case, the double quotes are not necessary, because no word splitting occures here after parameter expansion (since you are inside a [[....]]. Hence you can write simply [[ -z $BRANCH_EXISTS ]].
However, if the branch does not exist, grep will return a non-zero exit code, and the program will be aborted (due to your set -e. Therefore, the then branch of your conditional won't ever be executed, even if you would fix the conditional.
Related
I am attempting to use the [[ ]] operator in Bash and failing badly.
My script is:
#!/bin/bash
# Test driver for the ProtectDatae script
set -o xtrace
# [[ -z "$1" ]] || source="$1" && source=""
if [[ -z "%1" ]]
then
source=""
else
source=$1
fi
[[ -z "$2" ]] || target="$2" && target="" # This does not work
[[ -z "$3" ]] || sourceBackup="$3" && sourceBackup="/tmp/sourcebackup" # This does not work
source cmd.sh # Get a function to run a Linux command
if [[ -e "$sourceBackup" && "$sourceBackup" -ne "" ]]
then
# If a source backup directory is specified then get rid of any old directory and make a new backup
# and verify it. If OK, make the source directory be the source backup directory
# otherwise work directly in the source directory
if [[ -e "$sourceBackup" ]]
then
cmd "sudo rm -R $sourceBackup" "empty backup directory $sourceBackup failed"
cmd "cp -apu $source $sourceBackup" "backup home directory"
cmd "diff -aprN ~/$source/* $sourceBackup" "bad backup in $sourceBackup"
source="$sourceBackup"
fi
fi
exit 0
My command invocation is ./TestProtectData.sh "~" /tmp/jfghome /tmp/jfgbackup
The result of xtrace is:
+ source='~'
+ [[ -z /tmp/jfghome ]]
+ target=/tmp/jfghome
+ target=""
+ [[ -z /tmp/jfgbackup ]]
+ sourceBackup=/tmp/jfgbackup
+ sourceBackup=/tmp/sourcebackup
+ source cmd.sh
+ [[ -e /tmp/sourcebackup ]]
+ exit 0
What happens with the following line is the error. Both alternatives appear to be executed and the variable winds up being set incorrectly:
[[ -z "$2" ]] || target="$2" && target=""
I have tried both orders for && and || and they both give the same result with the variable target set to blank. On the next line, a similar thing happens with the variable sourceBackup set to the second alternative, and both alternatives appear to be executed. If I use the if then construct it works. What am I doing wrong?
What am I doing wrong?
Your intended logic doesn't match the bash constructs you're using. This line:
[[ -z "$2" ]] || target="$2" && target="" # This does not work
Breaks down to mean if 2 is not empty set target to $2. If that command succeeds, set target to "". The command to the left of && will always succeed - either the -z test succeeds or the target="$2" succeeds. Thus target="" always runs at the end.
You can use if ... ; then ...; else ...; fi or you can look at these ways to effect a ternary operator in bash, including:
#!/bin/bash -e
[[ -z "$3" ]] && sourceBackup="/tmp/sourcebackup" || sourceBackup="$3"
echo $sourceBackup
% ./t.sh 1 2 3
3
Here, if -z test succeeds we set sourceBackup to the default. If the test fails, $3 is not null and we set sourceBackup to $3.
To reiterate, this is not exactly the same as a tertiary operator. But if you get the order correct, it will work.
A plain assignement (foo=bar) always sets the status code to 0, so after target has been set to $2, it is immediately after set to empty. I would start by turning the logic inside out:
target= # Set to empty string
[[ -z $2 ]] && target=$2
However, this is redundant. You could easier simply just write
target=$2
without doing any [[...]]-test. If the second parameter is empty, target will be empty as well. If it is not empty, target will get that value.
There is one point to consider: In case you decide to turn on set -u, to catch uninitialized variables, a target=$2 would abort the script if there is no second parameter. Therefore, you could also write
target=${2:-}
which tells bash that a missing parameter is OK and should be treated as a null string.
Even though it is redundant, if you do not turn on -u, using ${2:-} shows your intent explicitly, and makes your program more maintainable.
I want to ensure that the given arguments are flags, by which I mean -x where x is some character or sequence of.
I have tried to do this with the following:
if [[ "$(echo '$1' | sed 's/[^-]//g')" -ne "-" ]];
then
echo "$usage"
exit
fi
Where my reasoning is that if - is not present when other characters are stripped it's not a flag.
This doesn't work though, and is obviously flimsy, but I don't know how to do this correctly.
# valid
script.sh -asdf
# invalid
script.sh sdf
You can do it this way to make sure $1 is starting with -:
if [[ "${1?}" != -* ]]; then
echo "$usage"
exit 1
fi
${1?} will fail the script if $1 is not available.
I want to execute echo only if one of the folders are not found?
However AEM_SEGMENTSTORE_LOCATION_AZURE is found but I still get "echo not found"
#!/bin/bash
AEM_SEGMENTSTORE_LOCATION="/opt/day/${AEM_RUNMODE}/crx-quickstart/repository/segmentstore"
AEM_SEGMENTSTORE_LOCATION_AZURE="/opt/day/crx-quickstart/repository/segmentstore"
[[ ! -d ${AEM_SEGMENTSTORE_LOCATION} ]] || [[ ! -d ${AEM_SEGMENTSTORE_LOCATION_AZURE} ]] && echo "not found"
In general, don't mix || and &&. The precedence is not what you expect. a || b && c is equivalent to (a || b) && c, but a && b || c is not the same as (a && b) || c. Get in the habit of using a proper if statement.
if [[ ! -d "$AEM_SEGMENTSTORE_LOCATION" || ! -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]; then
echo "not found"
fi
or
if ! [[ -d "$AEM_SEGMENTSTORE_LOCATION" && -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]; then
echo "not found"
fi
The precedence is wrong. You seem to be looking for AND anyway. You can easily fix this by changing it to
if [[ ! -d "$AEM_SEGMENTSTORE_LOCATION" ]] &&
[[ ! -d "$AEM_SEGMENTSTORE_LOCATION_AZURE" ]]
then
echo "$0: not found" >&2
fi
Notice also proper quoting of your variables {see When to wrap quotes around a shell variable; braces do not quote, and were basically useless here) and probably avoid uppercase variable names if these are private variables of yours (uppercase is reserved for system variables). Finally, the diagnostic message should probably go to standard error, and include the script's name; it should probably also say what was not found.
I have two variables declared but unset:
__var1=
__var2=
Now I set __var2 to have some value:
__var2=1
When I try to do a check like this:
[ -z "$__var1" -a -z "$__var2" ] || echo "Both missing!"
I am getting that message Both missing!. But that's incorrect.
Why is that? And how to do a proper check, to see if both of them are missing?
And if the user wants to check if the variable is really unset and not just having an empty value, you can do:
$ A=1234
$ [[ -z ${A+.} ]] && echo "Variable is unset."
$ A=
$ [[ -z ${A+.} ]] && echo "Variable is unset."
$ unset A
$ [[ -z ${A+.} ]] && echo "Variable is unset."
Variable is unset.
In which in your case it could be
[[ -z ${__var1+.} && -z ${__var2+.} ]] && echo "Both variables are unset!"
#Dave Schweissguth's answer makes a good point about the logic of your code, but there are also things to observe about the syntax:
[Update: The original form of the question used assignments such as $__var1= - this has since been corrected] In Bourne-like/POSIX-compatible shells you do not use the $ prefix when assigning a value, only when referencing it; thus, your assignments should read:
__var1=
__var2= # or, later: __var2=1
Your question is tagged bash, so the best bash way to write your could would be:
[[ -z $__var1 && -z $__var2 ]] && echo "Both missing!"
Note the use of [[ ... ]] rater than [ ... ], which obviates the need to double-quote the operands to -z.
By contrast, the most portable (POSIX-compliant) way is:
[ -z "$__var1" ] && [ -z "$__var2" ] && echo "Both missing!"
Your code prints "Both missing!" if it's not true (||) that both (-a) variables are empty (-z). You want to print the message if that IS true. Do that like this:
[ -z "$__var1" -a -z "$__var2" ] && echo "Both missing!"
I don't recall ever seeing a version of bash or test (what sh uses to evaluate the same expressions) without -z or -a, so as far as I know the above will work on any Unix-like system you're likely to find.
In the following, I would like check if a given variable name is set:
$ set hello
$ echo $1
hello
$ echo $hello
$ [[ -z \$$1 ]] && echo true || echo false
false
Since $hello is unset, I would expect the test to return true. What's wrong here? I would assume I am escaping the dollar incorrectly.
TYIA
You are testing if \$$1 is empty. Since it begins with a $, it is not empty. In fact, \$$1 expands to the string $hello.
You need to tell the shell that you want to treat the value of $1 as the name of a parameter to expand.
With bash: [[ -z ${!1} ]]
With zsh: [[ -z ${(P)1} ]]
With ksh: tmp=$1; typeset -n tmp; [[ -z $tmp ]]
Portably: eval "tmp=\$$1"; [ -z "$tmp" ]
(Note that these will treat unset and empty identically, which is usually the right thing.)