Multiple If Statements in Bash Script - bash

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" ]

Related

operation with files in shell ubuntu [duplicate]

I've been trying to compare whether two numbers in Bash are equal (and print a message if they are equal), but I'm getting some strange error messages for this simple program:
#!/bin/bash
fun2 (){
$x = 3
//#prog.sh: line 4: =: command not found
if [x == 3]
then
//#prog.sh: line 6: [x: command not found
echo "It's 3!"
fi
}
fun2
The corresponding errors are shown below the lines that caused those errors.
It must be:
if [ $x -eq 3 ]; then .....
If you prefer a more readable and self-explanatory code, use this syntax:
if test $x -eq 3; then .....
Explanation:
To compare integers you must use those operators (copied from man test):
INTEGER1 -eq INTEGER2
INTEGER1 is equal to INTEGER2
INTEGER1 -ge INTEGER2
INTEGER1 is greater than or equal to INTEGER2
INTEGER1 -gt INTEGER2
INTEGER1 is greater than INTEGER2
INTEGER1 -le INTEGER2
INTEGER1 is less than or equal to INTEGER2
INTEGER1 -lt INTEGER2
INTEGER1 is less than INTEGER2
INTEGER1 -ne INTEGER2
INTEGER1 is not equal to INTEGER2
operators == and != are for string comparison only.
For information: "[" command is an alias for system "test" command.
For the first error message, remove the dollar sign $ and no spaces are allowed around the equal sign =
x=3
For the second error message, insert a space and a dollar sign $ before x and a space after 3
if [ $x -eq 3 ]
As loentar correctly pointed out, it must be -eq and neither = nor ==.
Shell scripting wasn't really meant to be a full language, and it is heavily dependent upon other external commands to work.
Variables use a sigil which is that $ in front of them. A lot of shell scripting languages use variable sigils to help distinguish between a string and a variable.
For example:
foo=foo_value
echo foo foo $foo foo
Will print:
foo foo foo_value foo
Note that quotes are not necessary for the echo statement for strings. Windows Batch shell is very similar:
set foo = foo_value
echo foo foo %foo% foo
As you can see, the sigil is used when the variable is supposed to be expanded, but not when you define it. That's because Unix shells are intelligent shells. They munge the command line before it is even executed. The shell will substitute the environment variables before execution:
foo=bar
$foo="whose value is this" # Note the dollar sign!
echo The value of foo is $foo
echo The value of bar is $bar
This will print out:
The value of foo is foo
The value of bar is whose value is this
If you use the set -xv command, you'll see that $foo="whose value is this" is expanded to bar=whose value is this" before it is executed.
In Bourne style shells like KornShell and Bash, the if statement isn't what you think it is. The if command executes the statement, and will select the if clause if that command returns a zero value. For example:
cat "foo" > my_file # Create a one line file with the string foo in it.
if grep -q "foo" my_file # grep command will return a zero exit code if it finds foo
then
echo "The string 'foo' is in file my_file"
fi
Notice that the if clause isn't a Boolean statement. It's an actual command that is executed.
Somewhere early in Unix development, the test command was created. You can do a man test and see how to use it.
The test command allows you to do this:
foo=3
bar=3
if test foo -eq bar
then
echo "foo and bar are equal"
else
echo "foo and bar are not equal"
fi
If you do this:
$ ls -li /bin/test /bin/[
You will see that a command called [ actually exists, and is a hard link to the test command. This was created to make an if statement look more like a if statement you'll see in regular programming languages:
foo=3
bar=3
if [ foo -eq bar ]
then
echo "foo and bar are equal"
else
echo "foo and bar are not equal"
fi
It is the exact same script as above, but with [ instead of test.
This explains why you need the dash in many tests (it's a parameter to the test command, and parameters start with a dash!). It also explains why you need spaces around the [ and ]. These are actual Unix commands, and Unix commands must have white spaces around them, so the shell can process them.
Another issue is: Why does the shell have two different sets of tests for strings and numbers? That's because strings may contain nothing but digits, but are not really numeric. For example, if you do inventory, you might have a part number 001 and 01. Numerically, they're equal, but as strings, they're two different strings. There is no way for the shell script to know. Instead, you must let the shell script know if it's a numeric comparison or a string comparison.
Perl has similar issues since you don't declare variables as numeric or non-numeric:
Shell Script Perl
Boolean Operator Numeric String Numeric String
=================== ======= ====== ======= ======
Equals -eq = == eq
Not Equals -ne != != ne
Greater Than -gt > > gt
Less Than -lt < < lt
Greater or Equals -ge >= >= ge
Less Than or Equals -le <= <= le
You can try a few other things:
$ echo "*" # Echos the asterisk
$ echo * # No quotes: Prints all files in current directory
Notice again the shell expands the * before executing the echo command. This is the main difference between a shell script and a typical programming language. The shell first does expansion (fill in environment variables, glob substitution, and run sub-commands) before it actually executes the command.
The set -xv will show you what command is being executed, and how the shell expands the command before executing. Doing set +xv will shut that off. Play around with that, and you'll soon understand the shell a bit better.
the spaces are mandatory in the [ ] expression, so
if [ $x == 3 ]; then
you need a sigill on variables in the [ ] tests
For clarity, use == for equality rather than = even though both work. The former encourages the use of [[ and the latter can be confused with an assignment. Use (( … )) or -lt and -gt for numerical comparison.
if [[ "${my_var}" == "val" ]]; then
do_something
fi
if (( my_var == 3 )); then
do_something
fi
if [[ "${my_var}" -gt 3 ]]; then
do_something
fi

Unix Bash - Assign if/else to Variable

I have been creating to assign the output of if/else to a variable but keep on getting an error.
For Example:
mathstester=$(If [ 2 = 2 ]
Then echo equal
Else
echo "not equal"
fi)
So whenever I add $mathstester in a script, laid out like this:
echo "Equation: $mathstester"
It should display:
Equation: Equal
Do I need to lay it out differently? Is it even possible?
Putting the if statement in the assignment is rather clumsy and easy to get wrong. The more standard way to do this is to put the assignment inside the if:
if [ 2 = 2 ]; then
mathstester="equal"
else
mathstester="not equal"
fi
As for testing variables, you can use something like if [ "$b" = 2 ] (which'll do a string comparison, so for example if b is "02" it will NOT be equal to "2") or if [ "$b" -eq 2 ], which does numeric comparison (integers only). If you're actually using bash (not just a generic POSIX shell), you can also use if [[ "$b" -eq 2 ]] (similar to [ ], but with somewhat cleaner syntax for more complicated expressions), and (( b == 2 )) (these do numeric expressions only, and have very different syntax). See BashFAQ #31: What is the difference between test, [ and [[ ? for more details.
The correct way to use if is:
mathtester=$(if [ 2 = 2 ]; then echo "equal"; else echo "not equal"; fi)
For using this in multiline statements you might consider looking link.

sh shell double if statement

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
[[ 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.
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).
A little background...
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 test command (Yes, there's really one!).
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).
Using List Operators
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.
Bash's Special [[ compound command
In 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)
Mathematical Boolean Expression
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:
Use the original test (single square brackets) command and use the -a to string together two boolean statements in a single test.
Use list operators to string together two separate test commands (single square brackets).
Use the newer compound test command (double square brackets) that now include && and || as boolean operators, so you have a single compound test.
Forget about test command and just use mathematical evaluation (double parentheses) to evaluate boolean expressions.
Test Constructs Can Vary by Shell
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."
Be More Portable: Use the -a Test Operator
A 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.

Comparing variables in shell scripts

I have got a project that involves shell scripts and comparing values/variables within them. I have looked here and elsewhere on comparing variables and I have tried all the various examples given but I am running into something that is not as advertised. OS is Solaris10
I have created the following script as a learning experience-
#!/bin/ksh
stest()
{
if $X = $Y
then echo they're the same
else echo they're notthe same
fi
}
X=a
Y=a
stest
echo completed
I keep getting some variation of the following-
using shell sh or ksh-
#./test.sh
./test.sh[2]: a: not found
completed
using shell bash-
#./test.sh
./test.sh: line 5: a: command not found
completed
I have tried enclosing the if $X = $Y line in brackets and double brackets and I get back
[a: not found
or
[[a: not found
If I change the variables X and Y to the numeral "1" I get the same thing-
./test.sh[2]: 1: not found
I have tried enclosing things in single quotes, double quotes & backwards quotes.
Any help is appreciated.
After if, you need a shell command, like anywhere else. $X = $Y is parsed as a shell command, meaning $X is interpreted as a command name (provided that the value of the variable is a single word).
You can use the [ command (also available as test) or the [[ … ]] special syntax to compare two variables. Note that you need spaces on the inside of the brackets: the brackets are a separate token in the shell syntax.
if [ "$X" = "$Y" ]; then …
or
if [[ "$X" = "$Y" ]]; then …
[ … ] works in any shell, [[ … ]] only in ksh, bash and zsh.
Note that you need double quotes around the variables¹. If you leave off the quotes, then the variable is split into multiple words and each word is interpreted as a wildcard pattern. This doesn't happen inside [[ … ]], but the right-hand side of = is interpreted as a wildcard pattern there too. Always put double quotes around variable substitutions (unless you want the value of the variable to be used as a list of filename matching patterns, rather than as a string).
¹ Except on $X the [[ … ]] syntax.
This KornShell (ksh) script should work:
soExample.ksh
#!/bin/ksh
#Initialize Variables
X="a"
Y="a"
#Function to create File with Input
#Params: 1}
stest(){
if [ "${X}" == "${Y}" ]; then
echo "they're the same"
else
echo "they're not the same"
fi
}
#-----------
#---Main----
#-----------
echo "Starting: ${PWD}/${0} with Input Parameters: {1: ${1} {2: ${2} {3: ${3}"
stest #function call#
echo "completed"
echo "Exiting: ${PWD}/${0}"
Output :
user#foo:/tmp $ ksh soExample.ksh
Starting: /tmp/soExample.ksh with Input Parameters: {1: {2: {3:
they're not the same
completed
Exiting: /tmp/soExample.ksh
ksh version:
user#foo:/tmp $ echo $KSH_VERSION
#(#)MIRBSD KSH R48 2013/08/16

unary operator expected in shell script when comparing null value with string

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?

Resources