Monday, January 14, 2008

UNIX Tutorial for beginners2

Unix
Bourne Shell Programming


Table of Contents
1 Very simple Scripts ....................................................................................................4
1.1 Traditional hello world script .................................................... 4
1.2 A very simple backup script ..................................................... 4
2 Redirections ..............................................................................4
2.1 Sample: stdout 2 file .................................................................... 5
2.2 Sample: stderr 2 file ........................................................ 5
2.3 Sample: stdout 2 stderr ................................................................ 5
2.4 Sample: stderr 2 stdout ............................................................. 5
2.5 Sample: stderr and stdout 2 file ............................................ 6
3 Pipes ...............................................................................6
3.1 What they are and why you'll want to use them ......................... 6
3.2 Sample: simple pipe with sed ............................................... 6
3.3 Sample: an alternative to ls -l *.txt ....................................... 6
4 Variables........................................................................7
4.1 Sample: Hello World! using variables ................................... 7
4.2 Sample: A very simple backup script (little bit better) ........................... 7
4.3 Local variables ................................................................ 7
5 Conditional Statments ............................................................8
5.1 Dry Theory ................................................................. 8
5.2 Sample: Basic conditional example if .. then............................... 8
5.3 Sample: Basic conditional example if .. then ... else............................. 9
5.4 Sample: Conditionals with variables ......................................... 9
6 Loops for, while and until .......................................9
6.1 For sample ............................................................... 9
6.2 C-like for .................................................................................. 10
6.3 While sample .............................................................................. 10
6.4 Until sample ......................................................................... 10
7 Functions ...............................................................................10
7.1 Functions sample ..................................................................... 11
7.2 Functions with parameters sample ..................................................................... 11
8 User interfaces......................................................................12
8.1 Using select to make simple menus ................................................................... 12
8.2 Using the command line ............................................................... 12
9 Miscellaneous .............................................................................13
9.1 Reading user input with read ............................................................ 13
9.2 Arithmetic evaluation ................................................................... 13
9.3 Finding bash ............................................................................. 14
9.4 Getting the return value of a program .................................................. 14
10 Tables...................................................15
10.1 String comparison operators ................................................... 15
10.2 String comparison examples ................................................................ 15
10.3 Arithmetic operators ..................................... 16
10.4 Arithmetic relational operators ....................................................... 16
11 More Scripts .........................................................................16
11.1 Applying a command to all files in a directory. Error! Bookmark not defined. 11.2 Sample: A very simple backup script (little bit better) ............................. 16
11.3 File re-namer ..................................................................... 16
11.4 File renamer (simple) ........................................................... 18
12 When something goes wrong (debugging) ............................19
12.1 Ways Calling BASH ........................................................................ 19


1 Very simple Scripts

This tutorial will try to give you some hints about shell script programming strongly based on examples.
In this section you'll find some little scripts which will hopefully help you to understand some techniques.
1.1 Traditional hello world script
#!/bin/bash
echo Hello World
This script has only two lines. The first indicates the system which program to use to run the file.
The second line is the only action performed by this script, which prints 'Hello World' on the terminal.
If you get something like ./hello.sh: Command not found. Probably the first line '#!/bin/bash' is wrong, issue where is bash or see 'finding bash' to see how should you write this line.

1.2 A very simple backup script
#!/bin/bash
tar -cZf /var/my-backup.tgz /home/me/

In this script, instead of printing a message on the terminal, we create a tar-ball of a user's home directory. This is NOT intended to be used, a more useful backup script is presented later in this document.

2 Redirections
There are 3 file descriptors, stdin, stdout and stderr (std=standard).
Basically you can:
1. 1. redirect stdout to a file
2. 2. redirect stderr to a file
3. 3. redirect stdout to a stderr
4. 4. redirect stderr to a stdout
5. 5. redirect stderr and stdout to a file
6. 6. redirect stderr and stdout to stdout
7. 7. redirect stderr and stdout to stderr


1 'represents' stdout and 2 stderr.
A little note for seeing these things: with the less command you can view both stdout (which will remain on the buffer) and the stderr that will be printed on the screen, but erased as you try to 'browse' the buffer.
2.1 Sample: stdout 2 file
This will cause the output of a program to be written to a file.
ls -l > ls-l.txt
Here, a file called 'ls-l.txt' will be created and it will contain what you would see on the screen if you type the command 'ls -l' and execute it.

2.2 Sample: stderr 2 file
This will cause the stderr output of a program to be written to a file.
grep da * 2> grep-errors.txt
Here, a file called 'grep-errors.txt' will be created and it will contain what you would see the stderr portion of the output of the 'grep da *' command.

2.3 Sample: stdout 2 stderr
This will cause the stderr output of a program to be written to the same file descriptor than stdout.
grep da * 1>&2
Here, the stdout portion of the command is sent to stderr, you may notice that in different ways.

2.4 Sample: stderr 2 stdout
This will cause the stderr output of a program to be written to the same file descriptor than stdout.
grep * 2>&1


Here, the stderr portion of the command is sent to stdout, if you pipe to less, you'll see that lines that normally 'disappear' (as they are written to stderr) are being kept now (because they're on stdout).

2.5 Sample: stderr and stdout 2 file
This will place every output of a program to a file. This is suitable sometimes for cron entries, if you want a command to pass in absolute silence.
rm -f $(find / -name core) &> /dev/null
This (thinking on the cron entry) will delete every file called 'core' in any directory. Notice that you should be pretty sure of what a command is doing if you are going to wipe its output.


3 Pipes

This section explains in a very simple and practical way how to use pipes, and why you may want it.
3.1 What they are and why you'll want to use them
Pipes let you use (very simple, I insist) the output of a program as the input of another one

3.2 Sample: simple pipe with sed
This is very simple way to use pipes.
ls -l | sed -e "s/[aeio]/u/g"
Here, the following happens: first the command ls -l is executed, and it's output, instead of being printed, is sent (piped) to the sed program, which in turn, prints what it has to.

3.3 Sample: an alternative to ls -l *.txt
Probably, this is a more difficult way to do ls -l *.txt, but it is here for illustrating pipes, not for solving such listing dilemma.
ls -l | grep "\.txt$"
Here, the output of the program ls -l is sent to the grep program, which, in turn, will print lines which match the regex "\.txt$".



4 Variables

You can use variables as in any programming languages. There are no data types. A variable in bash can contain a number, a character, a string of characters.
You have no need to declare a variable, just assigning a value to its reference will create it.
4.1 Sample: Hello World! using variables
#!/bin/bash
STR="Hello World!"
echo $STR
Line 2 creates a variable called STR and assigns the string "Hello World!" to it. Then the VALUE of this variable is retrieved by putting the '$' in at the beginning. Please notice (try it!) that if you don't use the '$' sign, the output of the program will be different, and probably not what you want it to be.

4.2 Sample: A very simple backup script (little bit better)
#!/bin/bash
OF=/var/my-backup-$(date +%Y%m%d).tgz
tar -cZf $OF /home/me/

This script introduces another thing. First of all, you should be familiarized with the variable creation and assignation on line 2. Notice the expression '$(date +%Y%m%d)'. If you run the script you'll notice that it runs the command inside the parenthesis, capturing its output.
Notice that in this script, the output filename will be different every day, due to the format switch to the date command(+%Y%m%d). You can change this by specifying a different format.
Some more examples:
echo ls
echo $(ls)

4.3 Local variables
Local variables can be created by using the keyword local.
#!/bin/bash

HELLO=Hello
function hello { local HELLO=World echo $HELLO
}
echo $HELLO
hello
echo $HELLO

This example should be enough to show how to use a local variable.


5 Conditional Statements
Conditionals let you decide whether to perform an action or not, this decision is taken by evaluating an expression.
5.1 Dry Theory
Conditionals have many forms. The most basic form is: if expression then statement where 'statement' is only executed if 'expression' evaluates to true. '2<1' is an expression that evaluates to false, while '2>1' evaluates to true.xs
Conditionals have other forms such as: if expression then statement1 else statement2. Here 'statement1' is executed if 'expression' is true, otherwise 'statement2' is executed.
Yet another form of conditionals is: if expression1 then statement1 else if expression2 then statement2 else statement3. In this form there's added only the "ELSE IF 'expression2' THEN 'statement2'" which makes statement2 being executed if expression2 evaluates to true. The rest is as you may imagine (see previous forms).
A word about syntax:
The base for the 'if' constructions in bash is this:
if [expression];
then
code if 'expression' is true.
fi

5.2 Sample: Basic conditional example if .. then
#!/bin/bash
if [ "foo" = "foo" ]; then


echo expression evaluated as true
fi
The code to be executed if the expression within braces is true can be found after the 'then' word and before 'fi' which indicates the end of the conditionally executed code.

5.3 Sample: Basic conditional example if .. then ... else
#!/bin/bash if [ "foo" = "foo" ]; then echo expression evaluated as true else echo expression evaluated as false fi

5.4 Sample: Conditionals with variables
#!/bin/bash
T1="foo"
T2="bar"
if [ "$T1" = "$T2" ]; then

echo expression evaluated as true else echo expression evaluated as false fi


6 Loops for, while and until

In this section you'll find for, while and until loops.
The "for" loop is a little bit different from other programming languages. Basically, it let's you iterate over a series of 'words' within a string.
The while executes a piece of code if the control expression is true, and only stops when it is false (or an explicit break is found within the executed code.
The "until" loop is almost equal to the while loop, except that the code is executed while the control expression evaluates to false.
If you suspect that while and until are very similar you are right.
6.1 For sample
#!/bin/bash
for i in $( ls ); do
echo item: $i
done


On the second line, we declare i to be the variable that will take the different values contained in $( ls ).
The third line could be longer if needed, or there could be more lines before the done (4).
'done' (4) indicates that the code that used the value of $i has finished and $i can take a new value.
This script has very little sense, but a more useful way to use the for loop would be to use it to match only certain files on the previous example

6.2 C-like for
Fresh suggested adding this form of looping. It's a for loop more similar to C/perl... for.
#!/bin/bash
for i in `seq 1 10`;
do

echo $i
done


6.3 While sample
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 10 ]; do

echo The counter is $COUNTER
let COUNTER=COUNTER+1
done

This script 'emulates' the well known (C, Pascal, perl, etc) 'for' structure

6.4 Until sample
#!/bin/bash
COUNTER=20
until [ $COUNTER -lt 10 ]; do

echo COUNTER $COUNTER
let COUNTER-=1
done



8 User interfaces

8.1 Using select to make simple menus
#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
if [ "$opt" = "Quit" ]; then
echo done
exit elif [ "$opt" = "Hello" ]; then
echo Hello World
else

clear
echo bad option
fi
done

If you run this script you'll see that it is a programmer's dream for text based menus. You'll probably notice that it's very similar to the 'for' construction, only rather than looping for each 'word' in $OPTIONS, it prompts the user.

8.2 Using the command line
#!/bin/bash
if [ -z "$1" ]; then
echo usage: $0 directory
exit
fi
SRCD=$1
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD

What this script does should be clear to you. The expression in the first conditional tests if the program has received an argument ($1) and quits if it didn't, showing the user a little usage message. The rest of the script should be clear at this point.



9 Miscellaneous

9.1 Reading user input with read
In many occasions you may want to prompt the user for some input, and there are several ways to achieve this. This is one of those ways:
#!/bin/bash echo Please, enter your name read NAME echo "Hi $NAME!"
As a variant, you can get multiple values with read, this example may clarify this.
#!/bin/bash echo Please, enter your first name and last name read FN LN echo "Hi! $LN, $FN !"

9.2 Arithmetic evaluation
On the command line (or a shell) try this:
echo 1 + 1
If you expected to see '2' you'll be disappointed. What if you want BASH to evaluate
some numbers you have? The solution is this:
echo $((1+1))
This will produce a more 'logical' output. This is to evaluate an arithmetic expression.
You can achieve this also like this:
echo $[1+1]
If you need to use fractions, or more maths or you just want it, you can use bc to evaluate
arithmetic expressions.
if i ran "echo $[3/4]" at the command prompt, it would return 0 because bash only uses integers when answering. If you ran "echo 3/4|bc -l", it would properly return 0.75.
9.3 Finding bash
From a message from mike (see Thanks to) you always use #!/bin/bash .. you might was to give an example of How to find where bash is located. 'locate bash' is preferred, but not all machines have locate. 'find ./ -name bash' from the root dir will work, usually. Suggested locations to check: ls -l /bin/bash ls -l /sbin/bash ls -l /usr/local/bin/bash ls -l /usr/bin/bash ls -l /usr/sbin/bash ls -l /usr/local/sbin/bash (can't think of any other dirs offhand... I’ve found it in most of these places before on different system). You may try also 'which bash'.

9.4 Getting the return value of a program
In bash, the return value of a program is stored in a special variable called $?.
This illustrates how to capture the return value of a program, I assume that the directory dada does not exist. (This was also suggested by mike)
#!/bin/bash
cd /dada &> /dev/null
echo rv: $?
cd $(pwd) &> /dev/null
echo rv: $?


10 Tables
10.1 String comparison operators
.(1) s1 = s2
.(2) s1 != s2
.(3) s1 < s2
.(4) s1 > s2
.(5) -n s1
.(6) -z s1
.(1) s1 matches s2
.(2) s1 does not match s2
.(3) __TO-DO__
.(4) __TO-DO__
.(5) s1 is not null (contains one or more characters)
.(6) s1 is null

10.2 String comparison examples
Comparing two strings.
#!/bin/bash
S1='string'
S2='String'
if [ $S1=$S2 ];
then

echo "S1('$S1') is not equal to S2('$S2')" fi if [ $S1=$S1 ]; then
echo "S1('$S1') is equal to S1('$S1')" fi
I quote here a note from a mail, sent buy Andreas Beck, referring to use if [ $1 = $2 ].

This is not quite a good idea, as if either $S1 or $S2 is empty, you will get a parse error. x$1=x$2 or "$1"="$2" is better.
10.3 Arithmetic operators
+
-
*
/
% (remainder)
10.4 Arithmetic relational operators
-lt (<)
-gt (>)
-le (<=)
-ge (>=)
-eq (==)
-ne (!=)
C programmers should simple map the operator to its corresponding parenthesis.



11 More Scripts
11.1 Sample: A very simple backup script (little bit better)
#!/bin/bash
SRCD="/home/"
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD



12 When something goes wrong (debugging)
12.1 Ways Calling BASH
A nice thing to do is to add on the first line
#!/bin/bash -x
This will produce some interesting output information


13 Reference
1. 1. http://www.tldp.org/LDP/abs/html/
2. 2. http://www.freeos.com/guides/lsst/
3. 3. http://quong.best.vwh.net/shellin20/
4. 4. http://www.eng.hawaii.edu/Tutor/vi.html
5. 5. http://tutorials.beginners.co.uk/read/category/11/id/269

No comments: