Bash Shell: What is the differences in syntax? - bash

I've seen two ways in tutorials to do syntax for if statements in BASH shell:
This one wouldn't work unless I put quotes around the variable and added additional [ and ]:
if [[ "$step" -eq 0 ]]
This one worked without putting quotes around the variable and the additional [ and ] weren't needed:
if [ $step -ge 1 ] && [ $step -le 52 ]
Which is correct and best practice? What are the differences? Thanks!

"When referencing a variable, it is generally advisable to enclose its name in double quotes" -- http://tldp.org/LDP/abs/html/quotingvar.html
if [ $step -ge 1 ] && [ $step -le 52 ] can be replaced as
if [ "$step" -ge 1 -a "$step" -le 52 ]
if [[ "$step" -eq 0 ]] can be replaced as if [ "$step" -eq 0 ]
Also, suppose you have the following script:
#!/bin/bash
if [ $x -eq 0 ]
then
echo "hello"
fi
You get this error when you run the script -- example.sh: line 2: [: -eq: unary operator expected
But using if [ "$x" -eq 0 ]
You get a different error when you run the script -- example.sh: line 2: [: : integer expression expected
Thus, it is always best to put variables inside quotes...
if [[ .... ]] syntax is particularly useful when you have regex in the condition statement -- http://honglus.blogspot.com/2010/03/regular-expression-in-condition.html
EDIT: When we deal with strings --
#!/bin/bash
if [ $x = "name" ]
then
echo "hello"
fi
You get this error when you run the script -- example.sh: line 2: [: =: unary operator expected
But, if you use if [ "$x" = "name" ] it runs fine (i.e. no errors ) and if statement is evaluated as false, as value of x is null which does not match name.

Related

Shell script error : line 170: [: missing ']'

i have the error named in the tittle in shell scripts when i execute this:
if [ $[ $op1 % $op2 ] == 0 ] and [ $res -ne 0 ]
then
resp
else
divi
fi
thanks.
Your first line violates several shell syntax rules.
if [ $[ $op1 % $op2 ] == 0 ] and [ $res -ne 0 ]
and has no meaning in a shell. Just like in C the correct syntax is &&.
And math expressions use $(( ... )).
So you probably meant:
if [ $(( $op1 % $op2 )) == 0 ] && [ "$res" -ne 0 ]
I also added quoting to $res as otherwise expansion takes place. E.g. if $res equals *, it would not compare * to zero but it would expand *, replacing it with the first filename in the current directory and this could cause the test to be true despite $res being *. To prevent this, you must quote $res. You don't need quoting for $op1 and $op2 as in math expression no shell expansion is performed.

"[:too many arguments" error in BASH

I'm learning BASH through HackerRank.There's an exercise in which the lengths of the triangle is given and then you need to find whether the triangle is isosceles,scalene or equilateral.I wrote the following code:
read a
read b
read c
if [ [ "$a" -eq "$b" ] && [ "$b" -eq "$c" ] ]
then
echo "EQUILATERAL"
elif [ [ "$a" -eq "$b" ] || [ "$b" -eq "$c" ] ]
then
echo "ISOSCELES"
else
echo "SCALENE"
fi
But then I get the following error
solution.sh: line 4: [: too many arguments
solution.sh: line 7: [: too many arguments
solution.sh: line 7: [: too many arguments
Why is this happening? I tried long and hard to rectify it but nothing worked out
You can combine conditions either ommiting the surrounding brackets like this
if [ "$a" -eq "$b" ] && [ "$b" -eq "$c" ]
or by combining the conditions with -a/-o like this
if [ "$a" -eq "$b" -a "$b" -eq "$c" ]
see http://wiki.bash-hackers.org/commands/classictest#and_and_or
&& and || are Bash list operators. In a chain of commands, the next command is executed only if the previous command returned 0 (&&) or nonzero (||).
[ is an alias for the Bash internal test command and has arguments such as -eq or -ne. ] ends its command line. Type help test for more information.
So if you write a conditional expression, you do not put the list operators inside brackets.
Try, for example, this instead of the respective line in your code:
if [ "$a" -eq "$b" ] && [ "$b" -eq "$c" ]
then
[ isn't a grouping operator in bash, you can't use it to group tests.
there are a number of different ways to express the tests you want to make, numeric evaluation mode is probably easiest to read
if (( a == b && b == c ))
if (( a == b || b == c || c == a ))
This is going to break if you have decimal fractions, but will work fine for integers.
[ is a conditional command, like an alias for sh's test built-in command.
[[ is the same for bash which has more test options.
So make a choice between [ and [[ but not [ [ which means two command.
Example:
# [ [ -n 'test' ] ]
bash: [: too many arguments
# [ -n 'test' ] && echo $?
0
# [[ -n 'test' ]] && echo $?
0

Integer expression expected error in shell script

I'm a newbie to shell scripts so I have a question. What Im doing wrong in this code?
#!/bin/bash
echo " Write in your age: "
read age
if [ "$age" -le "7"] -o [ "$age" -ge " 65" ]
then
echo " You can walk in for free "
elif [ "$age" -gt "7"] -a [ "$age" -lt "65"]
then
echo " You have to pay for ticket "
fi
When I'm trying to open this script it asks me for my age and then it says
./bilet.sh: line 6: [: 7]: integer expression expected
./bilet.sh: line 9: [: missing `]'
I don't have any idea what I'm doing wrong. If someone could tell me how to fix it I would be thankful, sorry for my poor English I hope you guys can understand me.
You can use this syntax:
#!/bin/bash
echo " Write in your age: "
read age
if [[ "$age" -le 7 || "$age" -ge 65 ]] ; then
echo " You can walk in for free "
elif [[ "$age" -gt 7 && "$age" -lt 65 ]] ; then
echo " You have to pay for ticket "
fi
If you are using -o (or -a), it needs to be inside the brackets of the test command:
if [ "$age" -le "7" -o "$age" -ge " 65" ]
However, their use is deprecated, and you should use separate test commands joined by || (or &&) instead:
if [ "$age" -le "7" ] || [ "$age" -ge " 65" ]
Make sure the closing brackets are preceded with whitespace, as they are technically arguments to [, not simply syntax.
In bash and some other shells, you can use the superior [[ expression as shown in kamituel's answer. The above will work in any POSIX-compliant shell.
This error can also happen if the variable you are comparing has hidden characters that are not numbers/digits.
For example, if you are retrieving an integer from a third-party script, you must ensure that the returned string does not contain hidden characters, like "\n" or "\r".
For example:
#!/bin/bash
# Simulate an invalid number string returned
# from a script, which is "1234\n"
a='1234
'
if [ "$a" -gt 1233 ] ; then
echo "number is bigger"
else
echo "number is smaller"
fi
This will result in a script error : integer expression expected because $a contains a non-digit newline character "\n". You have to remove this character using the instructions here: How to remove carriage return from a string in Bash
So use something like this:
#!/bin/bash
# Simulate an invalid number string returned
# from a script, which is "1234\n"
a='1234
'
# Remove all new line, carriage return, tab characters
# from the string, to allow integer comparison
a="${a//[$'\t\r\n ']}"
if [ "$a" -gt 1233 ] ; then
echo "number is bigger"
else
echo "number is smaller"
fi
You can also use set -xv to debug your bash script and reveal these hidden characters. See https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-error-integer-expression-expected-934465/
./bilet.sh: line 6: [: 7]: integer expression expected
Be careful with " "
./bilet.sh: line 9: [: missing `]'
This is because you need to have space between brackets like:
if [ "$age" -le 7 ] -o [ "$age" -ge 65 ]
look: added space, and no " "
Try this:
If [ $a -lt 4 ] || [ $a -gt 64 ] ; then \n
Something something \n
elif [ $a -gt 4 ] || [ $a -lt 64 ] ; then \n
Something something \n
else \n
Yes it works for me :) \n
If you are just comparing numbers, I think there's no need to change syntax, just correct those lines, lines 6 and 9 brackets.
Line 6 before: if [ "$age" -le "7"] -o [ "$age" -ge " 65" ]
After: if [ "$age" -le "7" -o "$age" -ge "65" ]
Line 9 before: elif [ "$age" -gt "7"] -a [ "$age" -lt "65"]
After: elif [ "$age" -gt "7" -a "$age" -lt "65" ]

if, elif, else statement issues in Bash

I can't seem to work out what the issue with the following if statement is in regards to the elif and then. Keep in mind the printf is still under development I just haven't been able to test it yet in the statement so is more than likely wrong.
The error I'm getting is:
./timezone_string.sh: line 14: syntax error near unexpected token `then'
./timezone_string.sh: line 14: `then'
And the statement is like so.
if [ "$seconds" -eq 0 ];then
$timezone_string="Z"
elif[ "$seconds" -gt 0 ]
then
$timezone_string=`printf "%02d:%02d" $seconds/3600 ($seconds/60)%60`
else
echo "Unknown parameter"
fi
There is a space missing between elif and [:
elif[ "$seconds" -gt 0 ]
should be
elif [ "$seconds" -gt 0 ]
All together, the syntax to follow is:
if [ conditions ]; then
# Things
elif [ other_conditions ]; then
# Other things
else
# In case none of the above occurs
fi
As I see this question is getting a lot of views, it is important to indicate that the syntax to follow is:
if [ conditions ]
# ^ ^ ^
meaning that spaces are needed around the brackets. Otherwise, it won't work. This is because [ itself is a command.
The reason why you are not seeing something like elif[: command not found (or similar) is that after seeing if and then, the shell is looking for either elif, else, or fi. However it finds another then (after the mis-formatted elif[). Only after having parsed the statement it would be executed (and an error message like elif[: command not found would be output).
You have some syntax issues with your script. Here is a fixed version:
#!/bin/bash
if [ "$seconds" -eq 0 ]; then
timezone_string="Z"
elif [ "$seconds" -gt 0 ]; then
timezone_string=$(printf "%02d:%02d" $((seconds/3600)) $(((seconds / 60) % 60)))
else
echo "Unknown parameter"
fi
[ is a command (or a builtin in some shells). It must be separated by whitespace from the preceding statement:
elif [
I would recommend you having a look at the basics of conditioning in bash.
The symbol "[" is a command and must have a whitespace prior to it. If you don't give whitespace after your elif, the system interprets elif[ as a a particular command which is definitely not what you'd want at this time.
Usage:
elif(A COMPULSORY WHITESPACE WITHOUT PARENTHESIS)[(A WHITE SPACE WITHOUT PARENTHESIS)conditions(A WHITESPACE WITHOUT PARENTHESIS)]
In short, edit your code segment to:
elif [ "$seconds" -gt 0 ]
You'd be fine with no compilation errors. Your final code segment should look like this:
#!/bin/sh
if [ "$seconds" -eq 0 ];then
$timezone_string="Z"
elif [ "$seconds" -gt 0 ]
then
$timezone_string=`printf "%02d:%02d" $seconds/3600 ($seconds/60)%60`
else
echo "Unknown parameter"
fi
Missing space between elif and [ rest your program is correct. you need to correct it an check it out. here is fixed program:
#!/bin/bash
if [ "$seconds" -eq 0 ]; then
timezone_string="Z"
elif [ "$seconds" -gt 0 ]; then
timezone_string=$(printf "%02d:%02d" $((seconds/3600)) $(((seconds / 60) % 60)))
else
echo "Unknown parameter"
fi
useful link related to this bash if else statement

Integer comparison in bash

I need to implement something like:
if [ $i -ne $hosts_count - 1] ; then
cmd="$cmd;"
fi
But I get
./installer.sh: line 124: [: missing
`]'
What I am doing wrong?
The command [ can't handle arithmetics inside its test. Change it to:
if [ $i -ne $((hosts_count-1)) ]; then
Edit: what #cebewee wrote is also true; you must put a space in front of the closing ]. But, just doing that will result in yet another error: extra argument '-'
The ] must be a separate argument to [.
You're assuming you can do math in [.
if [ $i -ne $(($hosts_count - 1)) ] ; then
In bash, you can avoid both [ ] and [[ ]] by using (( )) for purely arithmetic conditions:
if (( i != hosts_count - 1 )); then
cmd="$cmd"
fi
The closing ] needs to be preceded by a space, i.e. write
if [ $i -ne $hosts_count - 1 ] ; then
cmd="$cmd;"
fi

Resources