Tuesday, April 1, 2008

Conditional Expressions in Shell Scripting

A conditional expression is used with the [[ compound command to test attributes of files and to compare strings. Word splitting and filename generation are not performed on the words between [[ and ]]. See "The Test Statement" for details of [[.
Each expression can be constructed from one or more of the following unary or binary expressions:

Condition Description :-a file True if file exists.
-b file True if file exists and is a block special file.
-c file True if file exists and is a character special file.
-d file True if file exists and is a directory.
-f file True if file exists and is an ordinary file.
-g file True if file exists and is has its setgid bit set.
-h file True if file exists and is a symbolic link.
-k file True if file exists and is has its sticky bit set.
-n string True if length of string is non-zero.
-o option True if option named option is on.
-p file True if file exists and is a fifo special file or a pipe.
-r file True if file exists and is readable by current process.
-s file True if file exists and has size greater than zero.
-t file_des True if file descriptor number file_des is open and associated with a terminal device.
-u file True if file exists and is has its setuid bit set.
-w file True if file exists and is writable by current process.
-x file True if file exists and is executable by current process. If file exists and is a directory, the current process has permission to search in the directory.
-z string True if length of string is zero.
-H file True if file exists and is a hidden directory
-L file True if file exists and is a symbolic link.
-O file True if file exists and is owned by the effective user ID of this process.
-G file True if file exists and its group matches the effective group ID of this process.
-S file True if file exists and is a socket.
file1 -nt file2 True if file1 exists and is newer than file2.
file1 -ot file2 True if file1 exists and is older than file2.
file1 -ef file2 True if file1 and file2 exist and refer to the same file.
str = pattern True if string, str, matches pattern. str != pattern True if string, str, does not match pattern.
str1 <> str2 True if str1 comes after str2 based on the ASCII value of their characters.
exp1 -eq exp2 True if exp1 is equal to exp2. exp1 -ne exp2 True if exp1 is not equal to exp2. exp1 -lt exp2 True if exp1 is less than exp2.
exp1 -gt exp2 True if exp1 is greater than exp2.
exp1 -le exp2 True if exp1 is less than or equal to exp2.
exp1 -ge exp2 True if exp1 is greater than or equal to exp2.
A compound expression can be constructed from these primitives by using any of the following, listed in decreasing order of precedence.

Compound Description

(expression) True, if expression is true. The round-brackets are used to group expressions. ! expression True if expression is false. expr1 && expr2 True, if expr1 and expr2 are both true. && means Logical-AND expr1 expr2 True, if either expr1 or expr2 is true. means Logical-OR
The Test Statement:
The syntax for the test statement should be in the form:
$ test c ..or.. $ [[ condition ]]
Where condition is one or more valid conditional statements. The syntax, [[ , represents the command word, 'test', but must always be closed with ]]. Because [[ is, in effect, a command word, it must be followed by at least one white-space character (space or TAB) and the closing brackets, ]] , must also be preceded by at least one white-space character.
The following test statement uses the Bourne shell compatible syntax.
$ [ condition ]
Note that the character, [, represents to command word, test and must be followed by at least one SPACE or TAB character. The closing square bracket must be preceded by at least one SPACE or TAB character.
The following test statement uses the Korn shell syntax.
$ [[ condition ]]
Again, that the characters, [[, represents to command word, test and must be followed by at least one SPACE or TAB character. The closing square brackets must be preceded by at least one SPACE or TAB character.
The AND and OR statements differ between the Bourne and the Korn shell syntax.
Bourne shell syntax:
$ [ condition1 -a condition2 ] # ( 1 AND 2) $ [ condition1 -o condition2 ] # ( 1 OR 2)
Korn shell syntax:
$ [[ condition1 && condition2 ]] # ( 1 AND 2) $ [[ condition1 condition2 ]] # ( 1 OR 2)
The -a and -o clauses can not be used inside the Korn shell-specific, [[...]], test statement.
Numeric Conditional Testing:
Numeric conditional testing can be carried out within double round-brackets. The following test statements are unique to the Korn shell.
$ ((condition))
The opening double round brackets need not be followed by a SPACE or TAB character. Nor do the closing double round brackets neet to be preceeded by a SPACE or TAB.
Numeric conditions can be:
Condition Description
((x==$y)) Test if x is equal to y. ((x!=$y)) Test if x is not equal to y. ((x>$y)) Test if x is greater than y. ((x=$y)) Test if x is greater than or equal to y. ((x<=$y)) Test if x is less than or equal to y. If numeric variables are used within the test condition, the variable name does not to be preceded by a dollar ($) character if the variable name is to the left of the equals (=) character. The following two test conditions would be treated as being identical: (($var==3)) Test if content of variable,var, is equal to 3. ((var==3)) Test if content of variable, var, is equal to 3. Note: Any special shell variable, such as # (number of arguments) or ? (return status value) do need to be preceeded by the $ character. (($#==3)) would be a valid test condition, whereas((#==3)) would not! Logic Testing (if, then, ..., fi): The logical state of a condition can be used to determine whether one or more command lines should be executed. The simplest form of locical branching is performed using the if conditional statement. The structure of an if statement can be any of the following. Note: The word "then" is a reserved word and must be treated as a command in its own right. If it is to appear on the same command line as the if statement, it must be preceded by a semi-colon (to separate the two commands). if condition_statement then ... series of commands to be executed ... fi is the same as if condition_statement ; then ... series of commands to be executed ... fi For readability, it is probably better to have the word, then, on a line of its own. if statements can be nested, as shown below. Each if must be closed by the command word fi (the word `if' reversed). if condition_statement then command line 1 command line 2 if condition_statement2 then commands_for_nested_if fi command line 3 command line 4 fi Logic Testing (if, then,... elif ... ,else ...): Alternative command sequences can be executed based on the TRUE or FALSE state of a condition test. Shown below are more forms for the if statement. if condition_statement then commands to be executed if condition is TRUE else commands to be executed if condition is FALSE fi Multiple conditions can be applied. For example: if condition_statement1 then commands to be executed if condition1 is TRUE elif condition_statement2 then commands to be executed if condition2 is TRUE elif condition_statement3 then commands to be executed if condition3 is TRUE else commands executed if preceding conditions are FALSE fi Note that each elif is followed by the separated command word, then. The entire statement is closed down by just one occurrence of the word fi. Any of the conditional statements, described on the preceding pages could be used where the words, condition_statement, appear in the examples shown above. Logic Testing (case ... esac): As an alternative to using if then ... fi, the Korn shell supports the use of the case statement. The syntax for the case statement is: case value in pattern1) commands to execute when value matches pattern1 ;; pattern2) commands to execute when value matches pattern2 ;; ... patternn) commands to execute when value matches patternn ;; esac Where value could be either: A variable's contents (substituted on the command line) or A single value returned by a command substitution. When value matches one of the patterns, no further attempt will be made to match any other patterns within the case statement. The pattern can be any shell pattern matching structure. Multiple, alternative patterns can be used when separated by the pipe () character. Pattern Matching within case ... esac: The patterns which can be used within case ... esac are: Pattern Description
abcd) The literal string of characters, `abcd'.
ab) The literal character, `a' or `b'.
a*) The letter `a' followed by zero or more (of any) characters
a*A*) The letter `a' or the letter `A' followed by zero or more occurrences of any character
[aA]*) The letter `a' or the letter `A' followed by zero or more occurrences of any character
[!aA]*) A string of 1 or more occurences of any character where the first character is not the letter `a' or `A'.
a????) A four-character string of characters where the first character is the letter `a'.
\)) A literal bracket `)'.
*) Any number (zero or more) of any character.
The last pattern, shown above, would normally be used as the last, "catch all", pattern match. For example:
case $var in
ab) echo "var contains the letter a or b" ;;
[AB]) echo "var contains the letter A or B" ;;
*) echo "var does not contain a, A, b or B" ;;
esac