I cannot figure out how to use a simple if/elif/else structure in bash. I cannot believe how something as trivial as that can be so unintuitive and difficult. I've already spent quite a bit of time fiddling around with that. What I want to do is something like that:
aaa="xxx"
if [[ $aaa -eq "bbb" ]]; then
echo "bbb"
elif [[ $aaa -eq "ccc" ]]; then
echo "ccc"
else
echo "something else"
fi
I've tried it with a single [, with two [[, with ((, with == instead of -eq, I'm really not a Linux guy and very confused about the syntax, I've seen all kinds of different syntaxes regardind if conditionals.
It always prints bbb, no matter what value aaa has.
Can somebody please explain to me how to do this so that it works?
-eq is for numeric comparison only, for more info consider reading:
Shell equality operators (=, ==, -eq)
Also, consider quoting the variables:
When to wrap quotes around a shell variable?
Changed -eq to ==:
Quoted the variables
#!/bin/bash
aaa="xxx"
if [[ "$aaa" == "bbb" ]]; then
echo "bbb"
elif [[ "$aaa" == "ccc" ]]; then
echo "ccc"
else
echo "something else"
fi
something else
Try it online!
Use -eq for numeric comparisons, not for strings. Also, you are using quotes incorrectly. Use double quotes to prevent field splitting when you expand variables. IOW, they are needed around variables, but not around literal strings (unless the literal string contains whitespace or characters that would be interpreted by the shell such as a backtick or a $, etc.). And don't use a string of if/else when a case statement is more appropriate. Overall:
#!/bin/sh
aaa="$1"
if [ "$aaa" = bbb ]; then
echo "bbb"
elif [ "$aaa" = ccc ]; then
echo "ccc"
else
echo "something else"
fi
case $aaa in
bbb) echo bbb;;
ccc) echo ccc;;
*) echo something else;;
esac
Regarding quotes: there is absolutely nothing wrong with using quotes as in if [ "$aaa" = "bbb" ]; or case "$aaa" in, but it is almost always a mistake to omit them as in if [ $aaa = "bbb" ] Omitting the quotes in case $aaa in or var=$aaa is allowed because field splitting does not happen in those cases, but it is certainly best practice to include the quotes in those cases. Generally, use quotes around varaibles. if [ $aaa = "bbb" ] is a huge source of potential bugs, and should be avoided.
Related
At the moment I am working on a blackjack game using shell script. I have most of the script working with functions however the method I am using to find out if the player/computer goes bust doesn't seem to work. Could anyone point me in the right direction. (I am new to shell script.) When running it it will throw syntax errors around the lines that begin elif and sometimes if. It also prints all of the 'echo' outputs in bustConfirm instead of only the one that is true.
Also yes, one of my functions is called bustCheck.
bustConfirm(){
bust='bust'
under='under'
if [ $userBust -eq $bust -a $systemBust -eq $bust ]
then
echo "You both went bust! Be more careful!"
endGameRepeat
elif [ $userBust -eq $bust -a $systemBust -eq $under ]
echo $userName "went bust! Congratulations" $systemName"!"
endGameRepeat
elif [ $userBust -eq $under -a $systemBust -eq $bust ]
then
echo $systemName "went bust! Congratulations" $userName"!"
endGameRepeat
else
echo "Nobody went bust! Well played!"
endGameScores
fi
}
bustCheck(){
if [ "$userScore" -gt 21 ]
then
echo $userName "is bust!"
userBust='bust'
else
userBust='under'
fi
if [ "$systemScore" -gt 21 ]
then
echo $systemName "is bust!"
systemBust='bust'
else
systemBust='under'
fi
bustConfirm
}
The idea is that I wanted to use an && in the bustConfirm function and then an || to get the player is bust or system is bust result if only one of them was bust.
Also just a pointer but in the bustCheck I am seeing userBust and systemBust to contain the words bust or under. I created the variables bust and under for the bustConfirm function.
systemScore, userScore, systemName and userName are set before when the script is running.
Hope I've given enough detail and formatted it properly, first proper post so I apologize if not!
Taking a quick look, I see that the first if statement doesn't have a space after the opening square bracket.
I also recommend you put quotes around your variable names in if statements. This is due to the way shell actually works. The bash shell is extremely intelligent, and before your program has a chance to do anything, it grabs the line, does its magic, and then presents the line to the processor.
For example:
foo=""
if [ $foo = "" ]
then
echo "Foo is blank"
fi
Seems simple enough. However, what happens is that your shell will grab the line, substitute the value of $foo for the string "$foo", and then execute the line. Since $foo is blank, your if statement will become:
if [ = "" ] # That's not right!
then
echo "Foo is blank"
fi
By using quotes, this:
foo=""
if [ "$foo" = "" ]
then
echo "Foo is blank"
fi
becomes:
foo=""
if [ "" = "" ]
then
echo "Foo is blank"
fi
And that is valid. Another thing you can do is use the new test format that uses double square brackets:
foo=""
if [[ $foo = "" ]]
then
echo "Foo is blank"
fi
This will always work even without the extra quotes, and is now recommended unless you have to have your program compatible with the original Bourne shell syntax.
One more thing you can do in debugging your shell script is to use set -xv which turns on verbose debugging. Each statement, before it is executed will be printed, then it will print again after the shell fills in variables, patterns, etc., and then execute. It's a great way to debug your program. Just put set -xv on the line before you want this verbose debugging mode and use set +xv to turn it off. (Yes, the - turns it on and + turns it off.)
Thanks alot David, great answer, could you also tell me what the best way to get the && or equivalent of it within this as I need to find out if they are both bust, or just one etc
As already mentioned in a comment, you can use either one of these two forms:
if [ "$foo" = "bar" ] && [ "$bar" = "foo" ]
or
if [[ $foo = "bar" && $bar = "foo" ]]
I am trying to make a bash script with the output based on the input.
My code looks like this:
#!/bin/bash
echo "Letter:"
read a
if a=3
then
echo "LOL"
fi
if a=4
then
echo "ROFL"
fi
But when I enter 3 or 4, I get both LOL and ROFL.
Is there a way for me to get LOL for 3 and ROFL for 4?
Sorry if I'm using incorrect terms and stuff, I'm new to bash scripting.
In bash, a=3 is an assignment, not a test. Use, e.g.:
if [ "$a" = 3 ]
Inside [...], the equal sign tests for string (character) equality. If you want to test for numeric value instead, then use '-eq` as in:
if [ "$a" -eq 3 ]
The quotes around "$a" above are necessary to avoid an "operator" error when a is empty.
bash also offers a conditional expressions that begin with [[ and have a different format. Many like the [[ format better (it avoids, for example, the quote issue mentioned above) but the cost is loss of compatibility with other shells. In particular, note that dash, which is the default shell (/bin/sh) for scripts under Debian-derived distributions, does not have [[.
Bash thinks you're trying to assign a variable by saying a=3. You can do the following to fix this:
Use the = operator whilst referencing the variable with a $, like so: if [[ $a = 3 ]]
Use the -eq operator, which is special and doesn't require you to reference the variable with a $, but may not be compatible with all sh-derived shells: if [[ a -eq 3 ]]. If you wish to use -eq without Bash reference the variable: if [[ $a -eq 3 ]]
Note:
The double square brackets [[ ... ]] are a preferred format with specifically Bash conditionals. [ ... ] is good with any sh-derived shell (zsh, tcsh, etc).
if a=3 will assign value 3 to variable a
unless a is readonly variable, if a=3 always returns TRUE
same for if a=4
To compare variable a with a value, you can do this if [ $a = 3 ]
so the script should change to
#!/bin/bash
echo "Letter:"
read a
if [ $a = 3 ]
then
echo "LOL"
fi
if [ $a = 4 ]
then
echo "ROFL"
fi
Since a is read from user input, there is possibility user key in:
non numeric value
a string with empty space
nothing, user may just press Enter key
so a safer way to check is:
if [ "x$a" = "x3" ]
s="STP=20"
if [[ "$x" == *"$s"* ]]
The if condition is always false; why?
Try this: http://tldp.org/LDP/abs/html/comparison-ops.html
string comparison
=
is equal to
if [ "$a" = "$b" ]
There is a difference in testing for equality between [ ... ] and [[ ... ]].
The [ ... ] is an alias to the test command:
STRING1 = STRING2 the strings are equal
However, when using [[ ... ]]
When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (==) or does not match (!=) the pattern, and 1 otherwise. Any part of the pattern may be quoted to force it to be matched as a string.
The same seems to be true with just the = sign:
$ foo=bar
$ if [[ $foo = *ar ]]
> then
> echo "These patterns match"
> else
> echo "These two strings aren't equal"
> fi
These patterns match
Note the difference:
$ foo=bar
> if [ $foo = *ar ]
> then
> echo "These patterns match"
> else
> echo "These two strings aren't equal"
> fi
These two strings aren't equal
However, there are a few traps with the [ $f00 = *ar ] syntax. This is the same as:
test $foo = *ar
Which means the shell will interpolate glob expressions and variables before executing the statement. If $foo is empty, the command will become equivalent to:
test = *ar # or [ = *ar ]
Since the = isn't a valid comparison operator in test, you'll get an error like:
bash: [: =: unary operator expected
Which means the [ was expecting a parameter found in the test manpage.
And, if I happen to have a file bar in my directory, the shell will replace *ar with all files that match that pattern (in this case bar), so the command will become:
[ $foo = bar ]
which IS true.
To get around the various issues with [ ... ], you should always put quotes around the parameters. This will prevent the shell from interpolating globs and will help with variables that have no values:
[ "$foo" = "*ar" ]
This will test whether the variable $foo is equal to the string *ar. It will work even if $foo is empty because the quotation marks will force an empty string comparison. The quotes around *ar will prevent the shell from interpolating the glob. This is a true equality.
Of course, it just so happens that if you use quotation marks when using [[ ... ]], you'll force a string match too:
foo=bar
if [[ $foo == "*ar" ]]
then
echo "This is a pattern match"
else
echo "These strings don't match"
fi
So, in the end, if you want to test for string equality, you can use either [ ... ] or [[ ... ]], but you must quote your parameters. If you want to do glob pattern matching, you must leave off the quotes, and use [[ ... ]].
To compare two strings in variables x and y for equality, use
if test "$x" = "$y"; then
printf '%s\n' "equal"
else
printf '%s\n' "not equal"
fi
To test whether x appears somewhere in y, use
case $y in
(*"$x"*)
printf '%s\n' "$y contains $x"
;;
(*)
printf '%s\n' "$y does not contain $x"
;;
esac
Note that these constructs are portable to any POSIX shell, not just bash. The [[ ]] construct for tests is not (yet) a standard shell feature.
I do not know where you came up with the *, but you were real close:
s="STP=20"
if [[ "STP=20" == "$s" ]]; then
echo "It worked!"
fi
You need to escape = using \ in the string s="STP=20"
s="STP\=20"
if [[ "STP\=20" == "$s" ]]; then echo Hi; else echo Bye; fi
I have two variables
var=""
var1=abcd
Here is my shell script code
if [ $var == $var1 ]; then
do something
else
do something
fi
If I run this code it will prompt a warning
[: ==: unary operator expected
How can I solve this?
Since the value of $var is the empty string, this:
if [ $var == $var1 ]; then
expands to this:
if [ == abcd ]; then
which is a syntax error.
You need to quote the arguments:
if [ "$var" == "$var1" ]; then
You can also use = rather than ==; that's the original syntax, and it's a bit more portable.
If you're using bash, you can use the [[ syntax, which doesn't require the quotes:
if [[ $var = $var1 ]]; then
Even then, it doesn't hurt to quote the variable reference, and adding quotes:
if [[ "$var" = "$var1" ]]; then
might save a future reader a moment trying to remember whether [[ ... ]] requires them.
Why all people want to use '==' instead of simple '=' ? It is bad habit! It used only in [[ ]] expression. And in (( )) too. But you may use just = too! It work well in any case. If you use numbers, not strings use not parcing to strings and then compare like strings but compare numbers. like that
let -i i=5 # garantee that i is nubmber
test $i -eq 5 && echo "$i is equal 5" || echo "$i not equal 5"
It's match better and quicker. I'm expert in C/C++, Java, JavaScript. But if I use bash i never use '==' instead '='. Why you do so?
i am testing with the shell script below:
#!/bin/ksh -x
instance=`echo $1 | cut -d= -f2`
if [ $instance == "ALL" ]
then
echo "strings matched \n"
fi
It's giving this error in the if condition:
: ==: unknown test operator
is == really not the correct syntax to use?
I am running on the command line as below
test_lsn_2 INSTANCE=ALL
Could anybody please suggest a solution.
Thanks.
To compare strings you need a single =, not a double. And you should put it in double quotes in case the string is empty:
if [ "$instance" = "ALL" ]
then
echo "strings matched \n"
fi
I see that you are using ksh, but you added bash as a tag, do you accept a bash-related answer?
Using bash you can do it in these ways:
if [[ "$instance" == "ALL" ]]
if [ "$instance" = "ALL" ]
if [[ "$instance" -eq "ALL" ]]
See here for more on that.
Try
if [ "$instance" = "ALL" ]; then
There were several mistakes:
You need double quotes around the variable to protect against the (unlikely) case that it's empty. In this case, the shell would see if [ = "ALL" ]; then which isn't valid.
Equals in the shell uses a single = (there is no way to assign a value in an if in the shell).
totest=$1
case "$totest" in
"ALL" ) echo "ok" ;;
* ) echo "not ok" ;;
esac
I'va already answered a similar question. Basically the operator you need is = (not ==) and the syntax breaks if your variable is empty (i.e. it becomes if [ = ALL]). Have a look at the other answer for details.