Like any programming languages, SHELL has conditions functionalities as well. Conditions is like if else if or switch cases. We'll go through one at a time.
If else if condition, like its name implies, is a value condition operator. It performs value checking sequentially based on the conditions list and executes the code block if the condition is right. A good way to write these conditions is:
if [ condition ]; then
....
elif [ condition ]; then
....
else
....
fi
Example:
#!/bin/sh
OS="$(uname -s)"
if [ "$OS" = "FreeBSD" ]; then
echo "This is FreeBSD"
elif [ "$OS" = "CYGWIN_NT-5.1" ]; then
echo "This is Cygwin"
elif [ "$OS" = "SunOS" ]; then
echo "This is Solaris"
elif [ "$OS" = "Darwin" ]; then
echo "This is MacOS"
elif [ "$OS" = "AIX" ]; then
echo "This is AIX"
elif [ "$OS" = "Minix" ]; then
echo "This is Minix"
elif [ "$OS" = "Linux" ]; then
echo "This is Linux"
else
echo "Unknown OS"
fi
then
keyword the same line as the if
or elif
. Case is also a conditional operator. The difference between if else if
and case
is that case
relies only on a single value or a single condition to determine the next course of action. A good style of writing is:
case "$value"; do
value1|valueOne)
...
;;
value2|valueTwo)
...
;;
*)
...
;;
done
The last case is the default when no other specific case is fulfilled. Here's an example converting from if else if.
#!/bin/sh
OS="$(uname -s)"
case "$OS" in
"FreeBSD")
echo "This is FreeBSD"
;;
"CYGWIN_NT-5.1")
echo "This is CYGWIN"
;;
"SunOS")
echo "This is Solaris"
;;
"Darwin")
echo "This is MacOS"
;;
"AIX")
echo "This is AIX"
;;
"Minix")
echo "This is Minix"
;;
"Linux")
echo "This is Linux"
;;
*)
echo "Unknown OS"
;;
done
;;
break case keyword as one line. It itself is an execution Notice that SHELL uses a [
to check condition? That's is called 'test'. Unlike a conventional programming languages, The SHELL's test's syntax has their own uniqueness. We'll look into each expressions closely.
Since everything in Unix is a file, there is definitely a set of filesystem flags. You can use these flags to check for file, directory, block device, character device, missing file, status, permission, group, etc.
[ -b "/path/to/file" ]
- check /path/to/file
is a block device. False if no.[ -c "/path/to/file" ]
- check /path/to/file
is a character file. False is no.[ -d "/path/to/directory" ]
- check /path/to/directory
is a directory. False is no.[ -e "/path/to/object" ]
- check /path/to/object exists
. False is no.[ -f "/path/to/file" ]
- check /path/to/file
is a file. False is no.[ -g "/path/to/file" ]
- check /path/to/file
has Group-ID set. False is no or missing file.[ -h "/path/to/file" ]
, [ -L "/path/to/file" ]
- check /path/to/file
is a symbolic link. Failed is no or missing file. If the final file is a symbolic link. It will not follow.[ -p "/path/to/file" ]
- check /path/to/file
is a FIFO pipe. False is no or missing file.[ -S "/path/to/file" ]
- check /path/to/file
is a socket. False is no or missing file.[ -s "/path/to/file" ]
- check /path/to/file
contain byte data. False is 0 byte or missing file.[ -r "/path/to/file" ]
- check /path/to/file
has read permission. False means no read permission or missing file.[ -w "/path/to/file" ]
- check /path/to/file
has write permission. False means no write permission or missing file.[ -x "/path/to/file" ]
- check /path/to/file
has execute permission. False means no execute permission or missing file.[ -u "/path/to/file" ]
- check /path/to/file
has user-ID description. False means no user-ID description is set or missing file.[ -t "/path/to/file" ]
- check /path/to/file
has file descriptor. False means no or missing file.[ -z "" ]
- check string is empty (length is zero). False otherwise.[ "string" ]
- check string exists (not null). False otherwise.[ "one" = "one" ]
- check strings are the same. False otherwise.[ "one" != "two" ]
- check strings are not the same. False otherwise.[ 1 -eq 1 ]
- check both integers are equal. False otherwise.[ 1 -ne 2 ]
- check both integers are not equal. False otherwise.[ 1 -gt 0 ]
- check the former integer is greater than the latter. False otherwise.[ 1 -ge 0 ]
- check the former integer is greater than or equal to the latter. False otherwise.[ 0 -lt 1 ]
- check the former integer is less than the latter. False otherwise.[ 0 -le 1 ]
- check the former integer is less than or equal to the latter. False otherwise.expr
, or using grep
command. Here are some examples :# variable manipulation
if [ "${string#*My}" == "$string" ]; then
echo "It's there!"
fi
# using grep
if echo "$string" | grep -q "My"; then
echo "It's there!"
fi
# using expr
if expr "$string" : "My" 1>/dev/null; then
echo "It's there";
fi
This is when a condition requires multiple expressions (all listed above), we usually use AND or OR cases. Example: if expression1 is true AND expression2 is true, then do this. Here are some practices:
[expression1] && [expression2]
- make logical checking for both expression1
and expression2
using AND logic. if either is false, the overall result is false.[expression1] || [expression2]
- make logical checking for both expression1
and expression2
using OR logic. if either is true, the overall result is true.[ expression3 ] && { [expression1] || [expression2]; }
- make logical checking inside { ... }
to run first before any other comparisons. In this case, expression1
and expression2
OR logic gets evaluated first and produced the first result. Then, using that result, expression3
gets evaluated against with using AND logic.#!/bin/sh
if [ "one" != "two" ] && { [ 1 -gt 0 ] || [ 2 -lt 0 ]; }; then
...
fi
That's all for SHELL comparison and conditions.