Conditions in bash scripts (if statements)

If you use     bash for scripting No doubt you will have to use a lot of conditions, for example, for a If then build or a While tie.   The syntax of these conditions may seem a bit overwhelming to learn and use. This tutorial aims to help the reader understand the conditions in bash and provides a comprehensive list of possibilities.   A small Amount of general shell knowledge is assumed.

Difficulty: Basic – Medium

Introduction

Bash presents a lot of built-in controls and comparisons, which are quite useful in many situations.   You have probably seen phrases like the following:

yes [$ foo -ge 3];   so

The condition in this example is essentially a command.   It may sound strange, but wrapping a comparison with brackets is the same as using the built-in test command, like this one:

if you try $ foo -ge 3;   so

If $ foo is G reater then or AND qual to 3, the block after ‘then’ will be executed.   If you always wondered why bash tends to use -ge or -eq instead of> = or ==, it’s because this type of condition originates in a command, where -ge and -eq are options.

And that’s what Yes It does this essentially, checking the exit status of a command.   I’ll explain it in more detail in the tutorial. There are also built-in controls that are more specific for deposits.   What  about this ?

yes [-f regular file];   so

The previous condition is true if the file ‘regular file’ exists 

It is a regular file.   A regular file means that it is not a block or device of characters, or a directory.   In this way, you can make sure of a usable. The file exists before doing something with it.   You can even check if a file is readable!

yes [-r readable file];   so

The above condition is true if the file ‘readable file’ exists Y It is readable   Easy, is not it?

The syntax of an if statement (a brief explanation)

The basic syntax of a If then statement is like this:

yes <condition> ;   so

< commands >

fi

The condition is, depending on its type, surrounded by certain brackets, for example   []   You can read about the different types later in the tutorial.   You can add commands that will be executed when the condition is false using the command other keyword, and use the elif (elseif) keyword to execute commands in another condition if the primary condition is false.   the plus Keyword always comes last.   Example:

yes [-r somefile];   so

content = $ (cat somefile)

elif [-f somebody];   so

echo “The file ‘somefile’ exists but can not be read in the script”.

plus

echo “The file ‘somefile’ does not exist”.

fi

A brief explanation of the example: first we verify if the file somefile is readable (“if [-r somefile]”).   If so, we read it in a variable.   If not, we verify if it really exists (“elif [-f somefile]”).   If that is true, we inform that it exists but it is not readable (if it were, we would have read the content).   If the file does not exist, we inform that too.   The condition in elif It only runs if the condition in Yes it was fake   The commands belonging to plus They only run if both conditions are false.

The basic rules of the conditions.

When you start writing and using your own conditions, there are some rules you should know to avoid mistakes that are hard to track.   Here are three important ones:

  1.  Always keep spaces between the brackets and verification / actual comparison .   The following will not work:

yes [$ foo -ge 3];   so

Bash will complain about a “disappeared”] ‘”.

  1.  Always finish the line before putting a new keyword like “then  .   Words yes,  to   continuation,  other   thing,  elif Y fi they are shell keywords, which means that they can not share the same line.   Place a “;” enter the previous declaration and the keyword or place the keyword at the beginning of a new line.   Bash will throw errors like “syntax error near the unexpected token fi ‘” if it does not.
  2.  It is a good habit to quote chain variables if you use them in conditions , because otherwise they are likely to cause problems if they contain
    Spaces and / or new lines.   By quoting I mean:

yes ["$ stringvar" == "tux"];   so

There are a few cases in which you should not appointment, but they are rare.   You will see one of them later in the tutorial.

In addition, there are two things that can be useful to know:

  1.  You can reverse a condition putting a “!” In front of him.   Example:

Yes [!   -f regular file];   so

Be sure to place the “!” Inside the supports!

  1.  You can combine conditions through the use of certain operators.   For the simple bracket syntax that we have been using so far, you can use “-a” to Y I for or .   Example:

yes [$ foo -ge 3 -a $ foo -lt 10];   so

The above condition will return true if $ foo contains an integer greater than or equal to 3 and L ess T ha 10. You can read more about these combined expressions in the respective condition syntaxes.

And, one more basic thing: do not forget that conditions can also be used in other affirmations, such as While Y until. It is beyond the scope of this tutorial to explain them, but you can read about them in the Bash guide for beginners .

Anyway, I ‘ve only shown you conditions in parentheses so far.   However, there is more syntax, as you will read in the next section.

Syntax of different conditions.

Bash presents different syntax for the conditions.   I will list the three:

  1. Syntax ofasingle bracket

This is the condition syntax that you have already seen in the previous paragraphs;   It is the oldest supported syntax .   It is compatible with three types of conditions:

  •  File-based conditions
    •  Allows different types of controls in a    Example:

yes [-L symboliclink];   so

The previous condition is true if the ‘symboliclink’ file exists and is a symbolic link.   For more file-based conditions see     table     down.

  •  Chain-based conditions
    •  It allows checks in a chain and comparison of chains.   Example one:

yes [-z "$ emptystring"];   so

The above condition is true if $ emptystring is an empty string or an uninitialized variable.   Example two:

yes ["$ stringvar1" == "cheese"];   so

The previous condition is true if $ stringvar1 contains only the string “cheese”.   For more chain-based conditions see     table     down.

  •  Arithmetic conditions (based on numbers)
    •  It allows to compare whole numbers.   Example:

yes [$ num -lt 1];   so

The previous condition returns true if $ num is less than 1. For more arithmetic conditions, see     table     down.

  1. Syntax of double bracket

It is possible that you have already found conditions between double brackets, which look like this:

yes [["$ stringvar" == * string *]];   so

The double-bracket syntax serves as an improved version of the simple bracket syntax;   It has mainly the same characteristics, but also some important differences with it.   I will list them here:

  •  The first difference can be seen in the previous example;   when comparing strings, the double-bracket syntax presents a shell balloon.   This means that   an asterisk (“*”) will literally expand to anything, as you probably know about the normal use of the command line.   Therefore, if $ stringvar contains the phrase “string” anywhere, the condition will return true.   Other shapes of shell balloons are also allowed.   If you want to match both “String” and “string”, you can use the following syntax:

yes [["$ stringvar" == * [sS] tring *]];   so

Note that only general shell globing is allowed.   Bash-specific things like {1 .. 4 } or {foo, bar} will not work.   Also, keep in mind that the globbing will not work if you quote the correct string .   In this case, you should leave it without quotes.

  •  The second difference It is that the division of words is avoided.   Therefore, you could omit placing quotation marks around the string variables and use a condition like the following without problems:

yes [[$ stringvarwithspaces! = foo]];   so

However, string variables are still a good habit, so I recommend continuing to do so.

  •  The third difference it consists of not expanding the file names.   I will illustrate this difference using two examples, starting with the previous situation of a single bracket:

yes [-a * .sh];   so

The previous condition will return true if there is a single file in the working directory that has a .sh extension.   If there is none, it will return false.   If there are several .sh files, bash will throw an error and stop running the script.   This is because * .sh has been expanded to the files in the working directory.   The use of double brackets avoids this:

yes [[-a-.sh]];   so

The above condition will return true only if there is a file in the working directory called “* .sh”, no matter what other .sh files exist.   The asterisk is taken literally because the double-bracket syntax does not expand the file names.

  •  The fourth difference is the addition of more familiar combination expressions, or, more specifically, the operators “&&” and “||”.   Example:

yes [[$ num -eq 3 && "$ stringvar" == foo]];   so

The previous condition returns true if $ num equals 3 and $ stringvar equals “foo”.   The -ay -or known for the syntax of a single bracket are also compatible.

Keep in mind that the Y operator has priority over the or operator, which means that “&&” or “-a” will be evaluated before “||” or “-o.”

  •  The fifth difference is that the double-bracket syntax allows the matching of regular expression patterns using the “= ~” operator.   Watch     table     for more information.
  1. Syntax of double parentheses

There is also another syntax for arithmetic conditions (based on numbers), most likely adopted from the Korn shell:

yes (($ num <= 5));   so

The above condition is true if $ num is less than or equal to 5. This syntax may seem more familiar to programmers.   It has all the “normal” operators, such as “==”, “<” and “> =”.   Supports expressions that combine “&&” and “||” (But not the expressions -and -o!).   It is equivalent to the built-in let command.

Table of conditions

The following table lists the condition possibilities for the syntax of one and two brackets.   Save a single exception, the examples are given in bracket syntax, but they are always compatible with double brackets.

 1. File-based conditions:
ConditionRight, yesExample / explanation
[-an existing file]the file ‘existingfile’ exists.yes [-a tmp.tmp];   so
rm -f tmp.tmp # Make sure we do not bother an old temporary file
fi
[-b blockpecialfile]the ‘blockspecialfile’ file exists and is a special block.Special block files are special kernel files found in / dev, and are used primarily for ATA devices such as hard drives, cd-roms and floppy disks.

yes [-b / dev / fd0];   so
dd if = floppy.img of = / dev / fd0 #    Write an image on a floppy disk.
fi

[-c characters special file]The file ‘characterspecialfile’ exists and has a special character.Special character files are special kernel files found in / dev, used for all kinds of purposes (audio hardware, tty’s , but also / dev / null).

yes [-c / dev / dsp];   so
cat raw.wav> / dev / dsp #    This really works for certain raw wav files
fi

[-d directory]‘directory’ file exists and is a directory.In the UNIX style, directories are a special type of file.

yes [-d ~ / .kde];   so
echo “You seem to be a kde user”.
fi

[-e existing file]the file ‘existingfile’ exists.(same as -a, see that entry for an example)
[-f regular file]the file ‘regular file’ exists and is a regular file.A normal file is not a special file of blocks or characters or a directory.

yes [-f ~ / .bashrc];   so
source ~ / .bashrc
fi

[-g sgidfile]the file ‘sgidfile’ exists and is set-group-ID.When the SGID bit is set in a directory, all the files created in that directory will inherit the group from the directory.

yes [-g.   ];   so
echo “The created files inherit the group ‘$ (ls -ld. | awk’ {print $ 4} ‘)’ from the working directory”.
fi

[-G fileownedbyeffectivegroup]the file ‘fileownedbyeffectivegroup’ exists and is owned by the effective group ID.The effective group ID is the primary group ID of the user who runs.

Yes [!   -G file];   so #    An exclamation point reverses the result of the condition that follows it.
chgrp $ (id -g) file #    Change the group if it is not the cash.
fi

[-h symboliclink]The ‘symboliclink’ file exists and is a symbolic link.yes [-h $ pathtofile];   so
pathtofile = $ (readlink -e $ pathtofile) # Make sure that $ pathtofile contains the actual file and not a symbolic link.
fi
[-k stickyfile]the ‘stickyfile’ file exists and has its configuration bit set.The sticky bit has     a whole history   , but now it is used to prevent global writing directories from deleting their content from anyone.

Yes [!   -k / tmp];   so #    An exclamation point reverses the result of the condition that follows it.
echo “Warning!   Anyone can delete and / or rename their files in / tmp! ”
fi

[-L symboliclink]The ‘symboliclink’ file exists and is a symbolic link.(same as -h, see that entry for an example)
[-N modifiedsincelastread]the file ‘modifiedsincelastread’ exists and was modified after the last reading.yes [-N / etc / crontab];   so
killall -HUP crond #    SIGHUP causes crond to reread all the crontabs.
fi
[-O fileownedbyeffectiveuser]the file ‘fileownedbyeffectiveuser’ exists and is owned by the user who runs the script.yes [-O file];   so
chmod 600 # file    It makes the file private, which is a bad idea if you do not own it
fi
[-p namedpipe]the ‘namedpipe’ file exists and is a named pipe.A named pipe is a file in / dev / fd / that can be read only once.   Watch     my bash tutorial     For a case in which it is used.

yes [-p $ file];   so
cp $ file tmp.tmp #    Make sure we can read
File = “tmp.tmp”       #    The file as many times as  we want
fi

[-r readable file]the file ‘readablefile’ exists and is readable for the script.yes [-r file];   so
content = $ (cat file) #    Set $ ​​content to the contents of the file.
fi
[-s file not empty]the file ‘nonemptyfile’ exists and has a size of more than 0 bytes.yes [-s logfile];   so
gzip logfile       #    Backup of the old log file
touch the log file #    Before creating a new one.
fi
[-S socket]file ‘socket’ exists and is a socket.A socket file is used for interprocess communication and has an interface similar to a network connection.

yes [-S /var/lib/mysql/mysql.sock];   so
mysql -socket = / var / lib / mysql / mysql.sock # Watch    this advice from MySQL
fi

[-t openterminal]The file descriptor ‘openterminal’ exists and refers to an open terminal.Virtually everything is done with files in Linux / UNIX, and the terminal is no exception.

yes [-t / dev / pts / 3];   so
echo -e “nHello there is.   Message from terminal $ (tty) to you. “> / Dev / pts / 3 # Anyone who uses that terminal will see this message!
fi

[-u suidfile]the file ‘suidfile’ exists and is set-user-ID.The configuration of the suid bit in a file causes the execution of that file to be done with the credentials of the owner of the file, not the user who executes it.

yes [-u executable];   so
echo “Running executable program as user $ (ls -l executable | awk ‘{print $ 3}’)”.
fi

[-w writeablefile]the file ‘writablefile’ exists and can be written to the script.yes [-w / dev / hda];   so
grub-install / dev / hda
fi
[-x executable file]the file ‘executable file’ exists and is executable for the script.Note that the execution permission in a directory means that you can search (you can see what files it contains).

yes [-x / root];   so
echo “You can see the contents of the / root directory”.
fi

[newerfile -nt olderfile]the file ‘newerfile’ was changed more recently than ‘olderfile’, or if ‘newerfile’ exists and ‘oldfile’ does not exist.if [story.txt1 -nt story.txt];   so
echo “story.txt1 is newer than story.txt;   I suggest continuing with the first. ”
fi
[oldfile -ot newerfile]the file ‘olderfile’ was changed more time ago than ‘newerfile’,or if ‘newerfile’ exists and ‘oldfile’ does not exist.if [/ mnt / remote / remotefile -ot localfile];   so
cp -f localfile / mnt / remote / remotefile #  Make sure that the remote location also has the most recent version of the file
fi
[same file -ef]the ‘equal’ file and the ‘file’ refer to the same device / inode number.yes [/ dev / cdrom -ef / dev / dvd];   so
echo “Your main CD drive seems to read DVD, too.”
fi
 2. Chain-based conditions:
ConditionRight, yesExample / explanation
[STRING1 == STRING2]STRING1 is equal to STRING2.yes [“$ 1” == “moo”];   so
echo $ cow #    Have you ever tried running ‘apt-get moo’?
Note: You can also use a single “=” instead of a double.
[STRING1! = STRING2]STRING1 is not equal to STRING2.yes [“$ userinput”! = “$ Password”];   so
echo “Access Denied!   Incorrect password!”
Output 1 #    Stop the execution of the script here
fi
[STRING1> STRING2]STRING1 is sorted after STRING2 in the current locale (lexically).The backslash before the angled support is there because the support must escape to be interpreted correctly.   As an example we have a base    bubble ordering   :

(Do not feel embarrassed if you do not understand this, it’s a more complex example)

array = (linux tutorial blog)
swaps = 1
while ((swaps> 0));   do

swaps = 0
for ((i = 0; i <(($ {# array [@]} – 1)); i ++));   do
if [“$ {array [$ i]}”> “$ {array [$ ((i + 1))]}”], then #    Here is the classification condition
tempstring = $ {array [$ i]}
array [$ i] = $ {array [$ ((i + 1))]}
array [$ ((i + 1))] = $ tempstring
((swaps = swaps + 1))
fi
fact
fact
echo $ {array [@]} #    Returns “blog linux tutorial”

[STRING1 <STRING2]STRING1 is ordered before STRING2 in the current locale (lexically).
[-n NONEMPTYSTRING]NONEMPTYSTRING has a length greater than zero.This condition only accepts valid strings, so be sure to quote everything you have given.

yes [-n “$ userinput”];   so
userinput = parse ($ userinput) # Only analyze if the user really gave some input.
fi

Note that you can also omit the “-n”, since the brackets with only one string behave the same.

[-z EMPTYSTRING]EMPTYSTRING is an empty string.This condition also accepts entries without a string, such as an uninitialized variable:

yes [-z $ uninitializedvar];   so
uninitializedvar = ” initialized” #    -z returns true in an uninitialized variable, so we initialize it here.
fi

Only the double-bracket syntax:
[[STRING1 = ~ REGEXPATTERN]]
STRING1 matches REGEXPATTERN.If you are familiar with regular expressions, you can use these conditions to match regular expressions.

if [[“$ email” = ~ “b [A-Za-z0-9 ._% + -] + @ [A-Za-z0-9 .-] +. [A-Za-z] {2, 4} b ” ]];   so
echo “$ email contains a valid email address”.
fi

 3. Arithmetic conditions (based on numbers):
ConditionRight, yesExample / explanation
[NUM1 -eq NUM2]NUM1 is Equalizer to NUM2.These conditions only accept whole numbers.  The strings will be converted to whole numbers, if possible.   Some random examples:

yes [$?   -eq 0];   so #    $  Returns the exit status of the previous command.
echo “The previous command was executed successfully”.
fi

yes [$ (ps -p $ pid -o ni =) -ne $ (nice)];   so
echo “Process $ pid is running with a nice non-default value”
fi

yes [$ num -lt 0];   so
echo “Negative numbers not allowed;   coming out … ”
exit 1
fi

[NUM1 – a NUM2]NUM1 is N ot AND qual to NUM2.
[NUM1-gt NUM2]NUM1 is G reater T have NUM2.
[NUM1 -ge NUM2]NUM1 is G reater than o Equal a NUM2.
[NUM1 -lt NUM2]NUM1 is L ess T have NUM2.
[NUM1 -le NUM2]NUM1 is L is that o E qual a NUM2.
4. Miscellaneous conditions:
ConditionRight, yesExample / explanation
[-o shelloption]The shell option ‘shelloption’ is enabled.The shell options modify the behavior of bash, except some that can not be modified and that indicate the state of the shell.

Yes [!   -o checkwinsize] #    An exclamation point reverses the result of the condition that follows it.
echo “The checkwinsize shell option is disabled;  enabling it so you can change the size of your terminal window without problems “.
shopt -s checkwinsize #    This shell option is modifiable.
fi

yes [-o login_shell];   so
echo “This is a login shell.” #    This shell option is not modifiable

fi

With the double parentheses syntax, you can use the following conditions:

5. Syntax conditions of double parentheses:
ConditionRight, yesExample / explanation
((NUM1 == NUM2))NUM1 is equal to NUM2.These conditions only accept whole numbers.   The strings will be converted to whole numbers, if possible.   Some random examples:

if (($? == 0));   so #    $  Returns the exit status of the previous command.
echo “The previous command was executed successfully”.
fi

if (($ (ps -p $ pid -o ni =)! = $ (nice)));   so
echo “Process $ pid is running with a nice non-default value”
fi

if (($ num <0));   so
echo “Negative numbers not allowed;   coming out … ”
exit 1
fi

((NUM1! = NUM2))NUM1 is not equal to NUM2.
((NUM1> NUM2))NUM1 is greater than NUM2.
((NUM1> = NUM2))NUM1 is greater than or equal to NUM2.
((NUM1 <NUM2))NUM1 is less than NUM2.
((NUM1 <= NUM2))NUM1 is less than or    equal to NUM2.

After this dry information load, here is a little explanation for those who want to know more …

Diving a little deeper

I said I would tell more about the fact that Yes It basically checks the output status of the commands.   And so I will.   Bash’s basic rule when it comes to conditions is 0 is equal to true,> 0 is false .
That is more or less the opposite of many programming languages ​​where 0 is false and 1 (or more) is true.   The reason behind this is that shells like bash deal a lot with the programs.   According to the UNIX convention, programs use an exit status to indicate whether the execution was successful or an error occurred.   As a successful execution does not require any explanation, it only needs an exit status.   If there was a problem, however, it is useful to know what went wrong. Therefore, 0 is used for a successful execution and 1-255 to indicate what type of error occurred.   The meaning of the numbers 1-255 differs according to the program that returns them.

Anyway, Yes execute the block later so when the command returns 0. Yes, the conditions are commands.   The phrase [$ foo- ge 3] returns an exit status,   and the other two syntaxes too!   Therefore, there is a good trick you can use to quickly test a condition:

[$ foo - ge 3] && echo true

In this example, “echo true” is only executed if “[$ foo -ge 3]” returns 0 (true).   Why is that, I could ask.   It’s because bash only evaluates a condition when necessary.  When using the and to To combine the expression, both conditions must be true so that the expression of the combination becomes true.   If the first condition returns false, it does not matter what the second one returns;   the result will be false.   Therefore, bash does not evaluate the second condition, and that is the reason why “echo true” is not executed in the example.   This is the same for the or operator (“||”), where the second condition is not evaluated if the first condition is true.

Well, so much to dive. If you want to know more, I would like to point out the Advanced Bash-Scripting Guide and maybe the Bash Reference Manual  , or even this  System Administrator’s Guide for Bash Scripting .

conclusion

In this tutorial, you have begun to understand the many possibilities of     conditions in bash scripting   .   You have been able to read about the basic rules of writing anduse of conditions, about the three syntaxes and their properties, and maybe you took the opportunity to go a little deeper.   I hope you enjoyed reading as much as I enjoyed writing.   You can always come back here to check the conditions at.     the table     (Check that link to see the table directly), or to update your knowledge.   If you have any suggestions, additions or other comments, do not hesitate to comment.   Thanks for reading and happy scripting!

If you are looking for red hat training please contact us on bhavesh.pali@itsgroup.in. Innovative Technology Solutions is Red Hat Training Partner in India & ITS is offering a number of Red Hat Certification courses in multiple cities in India.