I like to think of programming (scripting) as a series of decisions made based on a system of reasoning — a process otherwise known as logic.
Logic is something that we all make use of every day when we decide what to do, and how and in what order to do it. In such cases, logic is usually an unconscious process based on actions and consequences.
We employ more conscious forms of logic when solving problems and deliberately working through processes to achieve a desired result.
Programming (scripting) employs a very deliberate form of logic, brought to pass through the use of control structures, which are dependent on various conditions presented to them.
In life and programming alike, results can be controlled by whether or not conditions are met, and how and to what degree they are met. But I gotta tell you, it’s a lot easier to anticipate and control conditions in a program than it is in real life!
Types of Control Structures
There are 5 control structures used in shell scripting.
Each control structure has its own specific purpose; half the fun is determining which one will best fit each need.
Let’s jump into a brief description of each control structure.
if
Use if to perform actions only if specific conditions are met.
If can be as simple as if ... then ... fi
or as comprehensive as if ... then ... elif ... then ... else ... then ... fi
.
case
Use case to perform one of multiple specified actions depending on the value of the variable/etc.
for
Use for to perform actions in a loop for each item/number/etc. specified.
while
Use while to perform actions in a loop while a specified condition returns true.
until
Use until to perform actions in a loop until specified conditions return true.
Control Commands
Several commands exist that allow additional control to be exerted from within a controlled structure.
Most often these commands are used from within loops or functions (which we will get into later).
These control commands are:
break
Use break to terminate or break out of a loop when a condition is met.
continue
Use continue to transfer control to upcoming code, while continuing execution of the loop.
exit
Use exit to exit the entire shell script without finishing, if a condition is met (or not met), etc.
return
Use return to send back (return) results/code/data from within a function/etc.
Comparison Operators
Comparison operators are used by control structures to compare values; they will return TRUE or FALSE.
Operator | Description |
---|---|
== | Equal |
>= | Greater Than or Equal |
> | Greater Than |
<= | Less Than or Equal |
< | Less Than |
!= | Not Equal |
Boolean Operators
Boolean operators are used by control structures to combine conditions and produce a more refined and logical TRUE/FALSE result.
Operator | Description |
---|---|
&& | Logical AND |
|| | Logical OR |
! | Logical NOT |
Tests (Relational Operators)
test
is a shell command that checks file types and compares values.
This command is very useful inside shell scripts when used to evaluate conditional expressions.
The test command can be used to determine if a file exists or is empty, what permissions the file has set, if a variables has a value, to compare the dates (ages) of two files, and to evaluate expressions, among other things.
The test operators will return either TRUE or FALSE. The available operators are:
Operator | Description |
---|---|
-b FILE | FILE exists and is block special |
-c FILE | FILE exists and is character special |
-d FILE | FILE exists and is a directory |
-e FILE | FILE exists |
-f FILE | FILE exists and is a regular file |
-g FILE | FILE exists and is set-group-ID |
-G FILE | FILE exists and is owned by the effective group ID |
-h FILE | FILE exists and is a symbolic link (same as -L) |
-k FILE | FILE exists and has its sticky bit set |
-L FILE | FILE exists and is a symbolic link (same as -h) |
-O FILE | FILE exists and is owned by the effective user ID |
-p FILE | FILE exists and is a named pipe |
-r FILE | FILE exists and read permission is granted |
-s FILE | FILE exists and has a size greater than zero |
-S FILE | FILE exists and is a socket |
-t FD | file descriptor FD is opened on a terminal |
-u FILE | FILE exists and its set-user-ID bit is set |
-w FILE | FILE exists and write permission is granted |
-x FILE | FILE exists and execute (or search) permission is granted |
FILE1 -ef FILE2 | FILE1 and FILE2 have the same device and inode numbers |
FILE1 -nt FILE2 | FILE1 is newer (modification date) than FILE2 |
FILE1 -ot FILE2 | FILE1 is older than FILE2 |
( EXPRESSION ) | EXPRESSION is true |
! EXPRESSION | EXPRESSION is false |
EXPRESSION1 -a EXPRESSION2 | both EXPRESSION1 and EXPRESSION2 are true |
EXPRESSION1 -o EXPRESSION2 | either EXPRESSION1 or EXPRESSION2 is true |
-n STRING | the length of STRING is nonzero |
-z STRING | the length of STRING is zero |
STRING1 = STRING2 | the strings are equal |
STRING1 != STRING2 | the strings are not equal |
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 |
In coming lessons, these operators (tests) will begin to make more sense, as they are used in examples.
Conclusion
There’s a saying that “practice makes perfect”, but I have to assume that either that is entirely not true, or I don’t practice enough.
In any case, practice does help, so have some fun while you’re at it. I once wrote a shopping list for my sister in code, making heavy use of control structures, and she not only understood it, but she also followed the instructions to the letter, and had fun doing it!
In coming lesson we’ll go into details of how to make use of each control structure, complete with fully-functional examples that you can try out.
[…] that you know about loops, the earlier mentions of control commands such as break, exit, and continue, should make more sense. They are often used in loops to break […]