Shellscript missing ] - bash

I have a shellscript that tells me missing ] in the line
if [ $status != "2" && $status != "3" && `echo "$temp1 > $upperLimit" | bc` = "1" ]
and also missing ] in the line
if [ $status = "2" && `cat motionsensordate` \> `date +%s` ]
Why is that?

The single [ doesn't support logical operators inside the brackets. You have to use them outside
if [ "$status" != 2 ] && [ "$status" != 3 ] ...
Use double quotes for variables in single brackets to prevent unary operator expected error when the variable is empty.
Or, switch to double brackets:
if [[ $status != 2 && $status != 3 ... ]]
Also, status different to 2 and 3 can be expressed by a pattern:
if [[ $status != [23] && ... ]]

And if you would like to (in addition to the answers here) group together conditions:
if [[ ( COND1 || COND2 ) && COND3 ]]
then
echo "$cmd"
break
fi

Related

Properly nesting conditionals in if statements

I had a set of conditionals working perfectly. However, I needed to tweak the algorithm (making it more complicated), which involved nested conditionals in bash.
For instance, here is one such block:
a1=C
a2=P
a3=E
a4=1
a5=7
a6=0
a7=4
a8=T
a9=K
a10=S
letters=$(echo {A..Z} | tr -d ' ')
if [ "$c3" != "$a3" ]
then
c3=${letters:$((RANDOM%26+1)):1}
if [ "$c3" == "$a3" ] && (( $count % $difficulty3 != 0 ))
then
c3=${letters:$((RANDOM%26+1)):1}
if [ "$c3" == "$a3" ] && [ [ "$c1" != "$a1" ] || [ "$c2" != "$a2" ] ]
then
c3=${letters:$((RANDOM%26+1)):1}
fi
fi
fi
The innermost if statement essentially checks, if c3 and a3 are equal, to make sure that c1 and a1 are also equal and that c2 and a2 are also equal. If not, it reassigns the variable c3 once more.
My thought is to do an if (true AND ( true OR true)) type logic, but this doesn't seem to work here. I get:
line 367: [: too many arguments
All the c and a variables are a single letter or numerical digit, so strings with spaces as I've seen in related SO posts on this subject are not causing the issue.
When I try doing double brackets instead of single around the whole thing, the script fails to run at all. Parentheses won't work since these aren't arithmetic operations... so I'm scratching my head now. It seems this is the proper way to do nested conditionals... what am I missing?
Square brackets look like special shell syntax but they're not at all. [ is just another name for test, and the closing ] is merely an argument that's ignored.
You can use curly braces, which are special syntax:
if [ "$c3" == "$a3" ] && { [ "$c1" != "$a1" ] || [ "$c2" != "$a2" ]; }
Parentheses also work. The extra ; isn't needed, but they create an unnecessary sub-shell, so I recommend curly braces:
if [ "$c3" == "$a3" ] && ( [ "$c1" != "$a1" ] || [ "$c2" != "$a2" ] )

Bash Syntax Error in conditional statement

I am trying to code a script that will tell the user if a triangle is isosceles, equilateral, or scalene. The error is occuring in line 7 (The elif line)
#!/bin/bash
read -p "Enter a number: " x
read -p "Enter a number: " y
read -p "Enter a number: " z
let "a = x + y + z"
if [ $x -eq $y ] && [ $y -eq $z ]
then echo "EQUILATERAL"
elif [[[ $x -eq $y ] && [ $y != $z ]] || [[ $x -eq $z ] && [ $z != $y ]] || [[ $y -eq $z ] && [ $z != $x ]]]
then echo "ISOSCELES"
elif [ $a -gt 1000 ]
then echo "Cannot equal more than 1000"
fi
I do realize that I could do the same thing with multiple elif lines, but I also have another elif as well and I want to keep it clean. Thanks all!
It seems like you think square brackets in the shell are like parentheses in C-style programming languages. That's not how they work. [ is a synonym for the test command, the condition it introduces ends with ]. And [[ is a special token that introduces a conditional expression, which ends with ]]. You can't mix them up, you can't add additional brackets like [[[, and they don't nest.
The grouping operators in the shell are { ... } and ( ... ); the latter also creates a subshell.
elif ( [[ $x -eq $y ]] && [[ $y != $z ]] ) || ( [[ $x -eq $z ]] && [[ $z != $y ]] ) || ( [[ $y -eq $z ]] && [[ $z != $x ]] )

AND, OR conditions in if statement

i have the following code
elif [ $text2 == 'LANDING' ] && [ "$text4" == 'FAIL' ] || [ "$text4" == '' ]; then
the condition is that text2 should be landing and text4 can either be fail or null.
How to evaluate the above command.
Please help if Im doing any wrong
Thanks in advance
You need to group them explicitly:
elif [ "$text2" = 'LANDING' ] &&
{ [ "$text4" = 'FAIL' ] || [ "$text4" = '' ]; }; then
Your attempt would succeed either of the following two conditions held:
text2 was LANDING and text4 was FAIL
text4 was empty or unset.
Since && and || have the same precedence, you could (perhaps surprisingly) write it without grouping:
elif [ "$text4" = '' ] || [ "$text4" = FAIL ] && [ $text2 == 'LANDING' ]; then
If you are using bash, you can use the [[ ... ]] command instead of [ ... ]. The grouping is required; the operators inside [[ ... ]] do have the precedences you would expect from other languages (that is, a || b && c is a || (b && c), not (a || b) && c).
elif [[ $text2 == 'LANDING' && ( "$text4" == 'FAIL' || "$text4" == '') ]]; then
Not particular recommended, but with bash, you can use extended globbing patterns in [[...]]
elif [[ $text2 == 'LANDING' && $text4 == #(FAIL|) ]]; then
Use curly braces or parentheses to group the || operands together. Parentheses look nicer, but they create a subshell which is inefficient, so curly braces are the way to go even though they're ugly.
elif [ $text2 == 'LANDING' ] && { [ "$text4" == 'FAIL' ] || [ "$text4" == '' ]; }; then
Notice that the curly braces require an extra semicolon.
Alternatively, if you're using bash you could use double square brackets, which allow for the slightly prettier:
elif [[ $text2 == 'LANDING' && ("$text4" == 'FAIL' || "$text4" == '') ]]; then

Bash if statement with multiple conditions throws an error

I'm trying to write a script that will check two error flags, and in case one flag (or both) are changed it'll echo-- error happened. My script:
my_error_flag=0
my_error_flag_o=0
do something.....
if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" && "$my_error_flag_o"="2" ]]; then
echo "$my_error_flag"
else
echo "no flag"
fi
Basically, it should be, something along:
if ((a=1 or b=2) or (a=1 and b=2))
then
display error
else
no error
fi
The error I get is:
line 26: conditional binary operator expected
line 26: syntax error near `]'
line 26: `if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" && "$my_error_flag_o"="2" ]]; then'
Are my brackets messed up?
Use -a (for and) and -o (for or) operations.
tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html
Update
Actually you could still use && and || with the -eq operation. So your script would be like this:
my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] || [ $my_error_flag_o -eq 2 ] || ([ $my_error_flag -eq 1 ] && [ $my_error_flag_o -eq 2 ]); then
echo "$my_error_flag"
else
echo "no flag"
fi
Although in your case you can discard the last two expressions and just stick with one or operation like this:
my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] || [ $my_error_flag_o -eq 2 ]; then
echo "$my_error_flag"
else
echo "no flag"
fi
You can use either [[ or (( keyword. When you use [[ keyword, you have to use string operators such as -eq, -lt. I think, (( is most preferred for arithmetic, because you can directly use operators such as ==, < and >.
Using [[ operator
a=$1
b=$2
if [[ a -eq 1 || b -eq 2 ]] || [[ a -eq 3 && b -eq 4 ]]
then
echo "Error"
else
echo "No Error"
fi
Using (( operator
a=$1
b=$2
if (( a == 1 || b == 2 )) || (( a == 3 && b == 4 ))
then
echo "Error"
else
echo "No Error"
fi
Do not use -a or -o operators Since it is not Portable.
Please try following
if ([ $dateR -ge 234 ] && [ $dateR -lt 238 ]) || ([ $dateR -ge 834 ] && [ $dateR -lt 838 ]) || ([ $dateR -ge 1434 ] && [ $dateR -lt 1438 ]) || ([ $dateR -ge 2034 ] && [ $dateR -lt 2038 ]) ;
then
echo "WORKING"
else
echo "Out of range!"
You can get some inspiration by reading an entrypoint.sh script written by the contributors from MySQL that checks whether the specified variables were set.
As the script shows, you can pipe them with -a, e.g.:
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
...
fi

Consolidate multiple if statements in Ksh

How can I consolidate the following if statements into a single line?
if [ $# -eq 4 ]
then
if [ "$4" = "PREV" ]
then
print "yes"
fi
fi
if [ $# -eq 3 ]
then
if [ "$3" = "PREV" ]
then
print "yes"
fi
fi
I am using ksh.
Why does this give an error?
if [ [ $# -eq 4 ] && [ "$4" = "PREV" ] ]
then
print "yes"
fi
Error:
0403-012 A test command parameter is not valid.
Try this:
if [[ $# -eq 4 && "$4" == "PREV" ]]
then
print "yes"
fi
You can also try putting them all together like this:
if [[ $# -eq 4 && "$4" == "PREV" || $# -eq 3 && "$3" == "PREV" ]]
then
print "yes"
fi
Do you just want to check if the last argument is "PREV"? If so, you can also do something like this:
for last; do true; done
if [ "$last" == "PREV" ]
then
print "yes"
fi
'[' is not a grouping token in sh. You can do:
if [ expr ] && [ expr ]; then ...
or
if cmd && cmd; then ...
or
if { cmd && cmd; }; then ...
You can also use parentheses, but the semantics is slightly different as the tests will run in a subshell.
if ( cmd && cmd; ); then ...
Also, note that "if cmd1; then cmd2; fi" is exactly the same as "cmd1 && cmd2", so you could write:
test $# = 4 && test $4 = PREV && echo yes
but if your intention is to check that the last argument is the string PREV, you might consider:
eval test \$$# = PREV && echo yes
Try this :
if [ $# -eq 4 ] && [ "$4" = "PREV" ]
then
print "yes"
fi

Resources