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?
CodePudding user response:
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.