Reputation: 5434
Can anyone see what I did wrong here? I keep getting the following error message: [[: not found
read INPUT
if [[ "$INPUT" -ge 1 ]] && [[ "$INPUT" -le 10 ]]; then
Do something
else
printf "Please enter a value between 1 and 10"
fi
Upvotes: 0
Views: 174
Reputation: 107040
It's complicated:
First, there are three separate ways of constructing your if
statement. Each way has its own unique syntax on how to join two booleans. (Actually, there are four ways since one way allows you to use list operators).
The if
command is a compound command built into the shell. The if
command executes the commands following the if
. If that command returns a zero value, the if
statement is considered true and the then clause executes. Otherwise, if it exists, the else clause will execute. Remember, the if
is just a command. You can do things like this:
if ! mv "$foo" "$bar"
then
echo "I can't move $foo to $bar"
exit 2
fi
What we need is a command to do some testing for us. If the test succeeds, that test command returns an exit code of zero. If not, it returns a non-zero exit code. Then, it could be used with the if
command!
The [
is an alias for the test command which was created to allow you to test files, strings, and numbers for the if
statement. (This is now a built in command in Bash, but its roots are actually part of /bin/test
and /bin/[
). These are the same:
if test "$foo" -eq "$bar"
then
...
fi
and
if [ "$foo" -eq "$bar" ]
then
...
fi
The test command (if you read the manpage has a -a
And test and a -o
Or test. You could have done:
if [ "$INPUT" -ge 1 -a "$INPUT" -le 10 ]
then
....
fi
This is a single test statement with three test parameters (-ge
, -a
, and -le
).
This isn't the only way to do a compound boolean test. The Bash shell has two list operators: &&
and ||
. The list operators go in between two commands. If you use &&
and the left hand command returns a non-zero exit code, the right hand command is not executed, and the entire list returns the exit value of the left-hand command. If you use ||
, and the left hand command succeeds, the right hand command is not executed, and the entire list returns a zero exit value. If the first command returns a non-zero exit value, the right-hand command is executed, and the entire list returns the exit value of the right-hand command.
That's why you can do things like this:
[ $bar -eq 0 ] || echo "Bar doesn't have a zero value"!
Since [ ... ]
is just a command that returns a zero or non-zero value, we can use these list operators as part of our test:
if [ "$INPUT" -ge 1 ] && [ "$INPUT" -le 10 ]
then
...
fi
Note that this is two separate tests and are separated by a &&
list operator.
[[
compound commandIn Kornshell, Zsh, and Bash, there are special compound commands for testing. These are the double square brackets. They appear to be just like the single square brackets command, but because they're compound commands, parsing is affected.
For example:
foo="This has white space"
bar="" #No value
if [ ! $foo = $bar ] # Doesn't work!
then
The shell expands $foo
and $bar
and the test will become:
if [ This has white space = ]
which just doesn't work. However,
if [[ $foo != $bar ]]
works fine because of special parsing rules. The double brackets allow you to use parentheses for grouping and &&
and ||
as boolean operators. Thus:
if [[ $INPUT -ge 1 && $INPUT -le 10 ]]
then
...
fi
Note that the &&
appears inside a single set of double square brackets. (Note there's no need for quotation marks)
Bash has built in mathematical processing including mathematical boolean expressions. If you put something between double parentheses, Bash will evaluate it mathematically:
if (( $INPUT >= 1 && $INPUT <= 10 ))
then
...
fi
In this case, (( $INPUT >= 1 && $INPUT <= 10 ))
is evaluated. If $INPUT
is between 1 and 10 inclusively, the mathematical expression will evaluate as true (zero exit code), and thus the then
clause will be executed.
So, you can:
test
(single square brackets) command and use the -a
to string together two boolean statements in a single test.test
commands (single square brackets).&&
and ||
as boolean operators, so you have a single compound test.Upvotes: 1
Reputation: 84343
As has been mentioned in other posts, [[
is a Bash shell keyword that isn't present in the Bourne shell. You can see this from a Bash prompt with:
type '[['
[[ is a shell keyword
In a Bourne shell, you will instead get "command not found."
-a
Test OperatorA more portable construct is to use the -a
test operator to join conditions (see man test
for details). For example:
if [ "$INPUT" -ge 1 -a "$INPUT" -le 10 ]; then
: # do something when both conditions are true
else
: # do something when either condition is false
fi
This will work in every Bourne-compatible shell I've ever used, and on any system that has a /bin/\[
executable.
Upvotes: -1
Reputation: 295403
[[
is not available in scripts which start with #!/bin/sh
, or which are started with sh yourscript
. Start your script with #!/bin/bash
if you want to use it.
See also http://mywiki.wooledge.org/BashGuide/Practices#Choose_Your_Shell
If you are going to use bash, by the way, there's a better syntax for numeric comparisons:
if (( input >= 1 && input <= 10 )); then ...
Note that lower-case variable names are preferred for local use -- all-upper-case names are reserved for environment variables and shell builtins.
If you're not going to use bash, use the POSIX test operator:
if [ "$input" -ge 1 ] && [ "$input" -le 10 ]; then ...
Note that when using [ ]
correct quoting is essential, whereas with [[ ]]
it is often superfluous; also, [ ]
is missing some extensions such as pattern-matching and regular-expression operators.
Upvotes: 6