Shell Programming
From Wikibooks, the open-content textbooks collection
Contents
|
[edit] Expansions
Expansions are required to deliver a value to script. We will discuss Arithmetic expansion and Parameter expansion here. Placing '$' prior to a variable expands its value.
Arithmetic expansion is done with $((operation)). Parameter expansion is done with ${parameter}.
Let's give an example of arithmetic expansion:
one=1 $(($one+1))
$(($one+1)) will have the value of 2.
Let's try to do some examples for parameter expansion. Let's say we want to remove a string 'Hello' from 'HelloBob'. The following will do the trick:
string='HelloBob'
${string%Bob}
${string%Bob} portion cuts out 'Bob' from end of variable string, so we are left with Hello as its output.
If variable string had value of 'HelloBobBob', ${string%%Bob} would do the same trick. The '%%' portion is required because it signifies to remove 'Bob' from end of variable string and do so further away from it. So, we are also left with 'Hello'.
If '%' is replaced with '#' and '%%' replaced with '##', this signifies the same meaning but this time from beginning of parameter, not from end. For example, the following code would remove 'Hello' from 'HelloBobBob':
${string#Hello}
{param-value} replaces param's value with 'value' fi param's original value is null.
{param-?value} prints param: value if param doesn't exist or null. It effectively aborts the command. {param+value} sets param to value if not null.
[edit] Control statements
The test command can be shortened to '[' and when this is done in control statements it is customary to end it with an accompanying ']' like '[ ]'.
[edit] Condition types
Condition types are used inside '[ ]' in order to test for a condition. Conditon types are divided into three categories - String comparison, Arithmetic comparison and File conditional.
[edit] String comparison
string1 = string2 equal string1 != string2 not equal -n string not null -z string null
[edit] Arithmetic comparison
expression1 -eq expression2 equal expression1 -ne expression2 not equal expression1 -gt expresssion2 greater than expression1 -ge expression2 greater than or equal to expresssion1 -lt expression2 less than expression1 -le expression2 less than or equal to
[edit] File conditional
-d file directory -e file file exists -f file file is regular file -g file set-group-id on file -r file readable file -s file non-zero sized file -u file set-user-id on file -w file writable file -x file executable file
[edit] If
The if statement has the following basic structure:
if [ condition of expressions ]; then fi
[edit] while
The while statement has the following basic structure:
while [ condition of expressions ]; do done
[edit] until
The until statement has the following basic structure:
until [ condition of expressions ]; do done
[edit] for
The for statement has the following basic structure:
for variable_name in value1 value2 ... do done
Every loop replaces variable_name's value with value1-2 and beyond.
[edit] Using && and || in control statements
The && and || can be used in control statements to represent nested loops like:
if [ condition1 ]; then
if [ condition 2 ]; then
fi
fi
as:
if [ condition1 ] && [ condition2 ]; then fi
[edit] Simple alarm clock - example code using control statements
The following code assumes bash environment with dialog utility present. $1 denotes value of first parameter. Infinite until loop in code line 18 drains memory after long time.
#!/bin/bash
#
# Simple alarm clock
# Author:mmmooonnnsssttteeerrr
# GPL released
time=`date +%H%M%S`
default=060000
quit=false
alarm=$1
help="Usage: alarm [%HH%MM%SS | default]\nDefault set to $default."
if [ -z "$alarm" ]; then
echo -e "$help"
exit 1
fi
if [ "$1" = "default" ]; then
alarm=$default
fi
until [ "$quit" = "true" ]; do
dialog --title "alarm2" --infobox "Current time(%H%M%S)=$time\nAlarm set at $alarm. Ctrl+c to exit." 4 40
sleep 1
time=`date +%H%M%S`
if [ "$time" = "$alarm" ]; then
snooze=true
until [ snooze = false ]; do
dialog --title "alarm2" --infobox "$alarm(%H%M%S) has arrived. Ctrl+c to exit." 3 70
echo -ne "\a"
sleep 1
done
quit=true
fi
done
exit 0
[edit] Simple alarm clock2 - example code using control statements
This is yet another alarm program. This time code is more efficient because it uses sleep command instead of infinite loop, so there is less risk of memory drainage. The trap command at code line 7 traps signal INT (ctrl-c) and performs cleanUp function as after action.
#!/bin/bash
# Author: mmmooonnnsssttteeerrr
# GPL
cleanUp() {
exit 1
}
trap cleanUp INT
help="Usage: alarm3 [%H] [%M]"
if [ -z $2 ]; then
echo $help
exit 1
fi
time=`date +%H`
alarm=$1
sleepfor=""
# Have to calculate how long to sleep.
# Hours
if [ $alarm -lt $time ]; then
sleepfor=`expr 24 - $time + $alarm`
sleepfor=`expr $sleepfor "*" 60`
else
sleepfor=`expr $alarm - $time`
sleepfor=`expr $sleepfor "*" 60`
fi
# Minutes
time=`date +%M`
alarm=$2
if [ $alarm -lt $time ]; then
sleepfor=`expr $(($sleepfor + 60 - $time + $alarm)) "*" 60`
else
sleepfor=`expr $(($sleepfor + $alarm - $time)) "*" 60`
fi
sleep $sleepfor
soundAlarm() {
for beep in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
do
[ $beep = 20 ] && break
echo -ne "\a"
sleep 1
done
}
soundAlarm
exit 0
[edit] Simple alarm clock 3
Actually, this code is the only one that does a reasonable job as an alarm clock. It is based on the following algorithm:
If a_h<T_h then (24-T_h+a_h)+a_m-T_m If a_h>=T_h then (a_h-T_h)+a_m-T_m
where a_h is alarm_hour, T_h is Time_hour, a_m is alarm_minute, T_m is Time_minute.
#!/bin/bash
#
# Beeps at a given time accurate to +-1min
# mmmooonnnsssttteeerrr
#
# GPL
#
alarm_hour=$1
alarm_min=$2
alarm_min=`expr $alarm_min "*" 60`
time_hour=`date +%H`
time_min=`date +%M`
time_min=`expr $time_min "*" 60`
if [ -z $2 ]; then
echo "alarm [%H] [%M]"
exit 1
fi
trap `exit 1` INT
if [ $alarm_hour -lt $time_hour ]; then
x=`expr $((24-$time_hour+$alarm_hour)) "*" 3600`
sleepfor=`expr $x + $alarm_min - $time_min`
else
y=`expr $((alarm_hour-time_hour)) "*" 3600`
sleepfor=`expr $y + $alarm_min - $time_min`
fi
echo $sleepfor
sleep $sleepfor
for beep in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
do
[ $beep = 20 ] && break
echo -ne "\a"
sleep 1
done
exit 0
[edit] expr command
[edit] expr 1 | expr 2
Expression 1 if expression 1 is non-zero, otherwise expression 2.
expr 1 | expr 2 1 0 -> Expression 1 1 1 -> Expression 1 0 0 -> Expression 2 0 1 -> Expression 2
[edit] expr 1 & expr 2
Zero if either expression is zero, otherwise expression 1.
expr 1 & expr 2 0 0 -> 0 1 0 -> 0 0 1 -> 0 1 1 -> Expression 1
[edit] Other operations in expr command
The expr command is useful in simple arithmetic operations using integers only.
expr 1 + 1
output: 2
Similarly,
expr 1 - 1 expr 1 * 1 expr 1 / 1 expr 1 % 1
which have following results, respectively: 0; 1; 1; 0. Note that % is modulus.
[edit] eval command
The eval command is like an extra $ in shell scripting. It evaluates a string and attempts to expand it as a variable. For example the following evaluates the string as $horse and expands the value of variable horse.
eval $"horse"
[edit] Regular expressions
Regular expressions are used generally to manipulate strings by external programs like find and grep.
[edit] Commonly used characters in regular expression
^ Anchor to beginning of line $ Anchor to end of line . Any single character [ ] Encloses pattern matching characters
[edit] Matching Characters
[:alnum:] Alphanumeric characters [:alpha:] Letters [:ascii:] ASCII characters [:blank:] Space or tab [:cntrl:] ASCII control characters [:digit:] Digits [:graph:] Noncontrol, nonspace characters [:lower:] Lowercase letters [:print:] Printable characters [:punct:] Punctuation characters [:space:] Whitespace characters, including vertical tab [:upper:] Uppercase letters [:xdigit:] Hexadecimal digits
[edit] Extended grep mode
The -E mode may be used in grep with the following characters preceded by '\'.
? Match is optional but may be matched at most once
"*" Must be matched zero or more times (without "")
+ Must be matched one or more times
{n} Must be matched n times
{n, } Must be matched n or more times
{n,m} Must be matched between n and m times
[edit] Examples of regular expression in use
Look for text in file, example_text_file, ending with e:
grep e$ example_text_file
Look for:
Crazy Monkey Crazy Donkey Cranky Money
in another_text_file:
grep -E Cra..\*[[:space:]][[:print:]]o... another_text_file
The above command tells grep to use extended mode, find "Cra", followed by any number of string, followed by space, followed by printable character, followed by "o", followed by three characters, and search this in another_text_file.
[edit] I/O Redirection
File descriptor (fd) 0 is stdin. Fd 1 is stdout. Fd 2 is stderr.
#!/bin/bash
tasklist=$1
exec 6<$tasklist
while read -u 6 raw
do
# Do for each line
done
exec 6<&-
In the above example, exec globally opens $tasklist file for reading by assigning fd 6. The read command then reads fd 6 source line by line until end of file. The exec globally closes fd 6 in the last line.
[edit] Arrays
To assign a value to an element of an array simply do
ArrayName[2]=ValueForArrayNameIndex2
To expand the value of an index of an array do
${ArrayName[2]} # This equals 'ValueForArrayNameIndex2'
The arrays don't need to be full or compact (ie. there can be null values between some interval of indexes).