1445 lines
31 KiB
Plaintext
1445 lines
31 KiB
Plaintext
BASH Programming - Introduction HOW-TO
|
||
by Mike G mikkey at dynamo.com.ar
|
||
Thu Jul 27 09:36:18 ART 2000
|
||
|
||
This article intends to help you to start programming basic-inter
|
||
mediate shell scripts. It does not intend to be an advanced docu
|
||
ment (see the title). I am NOT an expert nor guru shell program
|
||
mer. I decided to write this because I'll learn a lot and it might
|
||
be useful to other people. Any feedback will be apreciated, spe
|
||
cially in the patch form :)
|
||
______________________________________________________________________
|
||
|
||
Table of Contents
|
||
|
||
|
||
|
||
1. Introduction
|
||
|
||
1.1 Getting the latest version
|
||
1.2 Requisites
|
||
1.3 Uses of this document
|
||
|
||
2. Very simple Scripts
|
||
|
||
2.1 Traditional hello world script
|
||
2.2 A very simple backup script
|
||
|
||
3. All about redirection
|
||
|
||
3.1 Theory and quick reference
|
||
3.2 Sample: stdout 2 file
|
||
3.3 Sample: stderr 2 file
|
||
3.4 Sample: stdout 2 stderr
|
||
3.5 Sample: stderr 2 stdout
|
||
3.6 Sample: stderr and stdout 2 file
|
||
|
||
4. Pipes
|
||
|
||
4.1 What they are and why you'll want to use them
|
||
4.2 Sample: simple pipe with sed
|
||
4.3 Sample: an alternative to ls -l *.txt
|
||
|
||
5. Variables
|
||
|
||
5.1 Sample: Hello World! using variables
|
||
5.2 Sample: A very simple backup script (little bit better)
|
||
5.3 Local variables
|
||
|
||
6. Conditionals
|
||
|
||
6.1 Dry Theory
|
||
6.2 Sample: Basic conditional example if .. then
|
||
6.3 Sample: Basic conditional example if .. then ... else
|
||
6.4 Sample: Conditionals with variables
|
||
|
||
7. Loops for, while and until
|
||
|
||
7.1 For sample
|
||
7.2 C-like for
|
||
7.3 While sample
|
||
7.4 Until sample
|
||
|
||
8. Functions
|
||
|
||
8.1 Functions sample
|
||
8.2 Functions with parameters sample
|
||
|
||
9. User interfaces
|
||
|
||
9.1 Using select to make simple menus
|
||
9.2 Using the command line
|
||
|
||
10. Misc
|
||
|
||
10.1 Reading user input with read
|
||
10.2 Arithmetic evaluation
|
||
10.3 Finding bash
|
||
10.4 Getting the return value of a program
|
||
10.5 Capturing a commands output
|
||
10.6 Multiple source files
|
||
|
||
11. Tables
|
||
11.1 String comparison operators
|
||
11.2 String comparison examples
|
||
11.3 Arithmetic operators
|
||
11.4 Arithmetic relational operators
|
||
11.5 Useful commands
|
||
|
||
12. More Scripts
|
||
|
||
12.1 Applying a command to all files in a directory.
|
||
12.2 Sample: A very simple backup script (little bit better)
|
||
12.3 File re-namer
|
||
12.4 File renamer (simple)
|
||
|
||
13. When something goes wrong (debugging)
|
||
|
||
13.1 Ways Calling BASH
|
||
|
||
14. About the document
|
||
|
||
14.1 (no) warranty
|
||
14.2 Translations
|
||
14.3 Thanks to
|
||
14.4 History
|
||
14.5 More resources
|
||
|
||
|
||
______________________________________________________________________
|
||
|
||
1. Introduction
|
||
|
||
1.1. Getting the latest version
|
||
|
||
http://www.linuxdoc.org/HOWTO/Bash-Prog-Intro-HOWTO.html
|
||
|
||
|
||
|
||
1.2.
|
||
|
||
Requisites
|
||
|
||
Familiarity with GNU/Linux command lines, and familiarity with basic
|
||
programming concepts is helpful. While this is not a programming
|
||
introduction, it explains (or at least tries) many basic concepts.
|
||
|
||
|
||
|
||
1.3.
|
||
|
||
Uses of this document
|
||
|
||
This document tries to be useful in the following situations
|
||
|
||
· You have an idea about programming and you want to start coding
|
||
some shell scripts.
|
||
|
||
· You have a vague idea about shell programming and want some sort of
|
||
reference.
|
||
|
||
· You want to see some shell scripts and some comments to start
|
||
writing your own
|
||
|
||
· You are migrating from DOS/Windows (or already did) and want to
|
||
make "batch" processes.
|
||
|
||
· You are a complete nerd and read every how-to available
|
||
|
||
2.
|
||
|
||
Very simple Scripts
|
||
|
||
This HOW-TO 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.
|
||
|
||
|
||
2.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 whereis bash or see
|
||
|
||
2.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.
|
||
|
||
3.
|
||
|
||
All about redirection
|
||
|
||
3.1.
|
||
|
||
Theory and quick reference
|
||
|
||
There are 3 file descriptors, stdin, stdout and stderr (std=standard).
|
||
|
||
|
||
|
||
Basically you can:
|
||
|
||
1. redirect stdout to a file
|
||
|
||
2. redirect stderr to a file
|
||
|
||
3. redirect stdout to a stderr
|
||
|
||
4. redirect stderr to a stdout
|
||
|
||
5. redirect stderr and stdout to a file
|
||
|
||
6. redirect stderr and stdout to stdout
|
||
|
||
7. redirect stderr and stdout to stderr
|
||
|
||
1 'represents' stdout and 2 stderr.
|
||
|
||
A little note for seeing this 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.
|
||
|
||
3.2. Sample: stdout 2 file
|
||
|
||
This will cause the ouput 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.
|
||
|
||
3.3. Sample: stderr 2 file
|
||
|
||
This will cause the stderr ouput 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 con
|
||
tain what you would see the stderr portion of the output of the 'grep
|
||
da *' command.
|
||
|
||
3.4.
|
||
|
||
Sample: stdout 2 stderr
|
||
|
||
This will cause the stderr ouput of a program to be written to the
|
||
same filedescriptor than stdout.
|
||
|
||
|
||
grep da * 1>&2
|
||
|
||
|
||
|
||
Here, the stdout portion of the command is sent to stderr, you may
|
||
notice that in differen ways.
|
||
|
||
3.5. Sample: stderr 2 stdout
|
||
|
||
This will cause the stderr ouput of a program to be written to the
|
||
same filedescriptor 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 'dissapear' (as they are
|
||
written to stderr) are being kept now (because they're on stdout).
|
||
|
||
3.6. 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 com
|
||
mand is doing if you are going to wipe it's output.
|
||
|
||
4.
|
||
|
||
Pipes
|
||
|
||
This section explains in a very simple and practical way how to use
|
||
pipes, nd why you may want it.
|
||
|
||
|
||
4.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
|
||
|
||
4.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 pro
|
||
gram, which in turn, prints what it has to.
|
||
|
||
4.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 dilema.
|
||
|
||
|
||
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$".
|
||
|
||
5.
|
||
|
||
|
||
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.
|
||
|
||
|
||
|
||
5.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.
|
||
|
||
5.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 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)
|
||
|
||
5.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 enought to show how to use a local variable.
|
||
|
||
6.
|
||
|
||
Conditionals
|
||
|
||
Conditionals let you decide whether to perform an action or not, this
|
||
decision is taken by evaluating an expression.
|
||
|
||
|
||
6.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. 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
|
||
|
||
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
|
||
|
||
6.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.
|
||
|
||
6.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
|
||
|
||
|
||
|
||
6.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
|
||
|
||
|
||
7.
|
||
|
||
|
||
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
|
||
|
||
The while executes a piece of code if the control expression is true,
|
||
and only stops when it is false (or a 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.
|
||
|
||
|
||
7.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).
|
||
|
||
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
|
||
|
||
|
||
7.2.
|
||
|
||
C-like for
|
||
|
||
fiesh 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
|
||
|
||
|
||
7.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
|
||
|
||
7.4.
|
||
|
||
Until sample
|
||
|
||
|
||
|
||
#!/bin/bash
|
||
COUNTER=20
|
||
until [ $COUNTER -lt 10 ]; do
|
||
echo COUNTER $COUNTER
|
||
let COUNTER-=1
|
||
done
|
||
|
||
|
||
|
||
8.
|
||
|
||
Functions
|
||
|
||
As in almost any programming language, you can use functions to group
|
||
pieces of code in a more logical way or practice the divine art of
|
||
recursion.
|
||
|
||
Declaring a function is just a matter of writing function my_func {
|
||
my_code }.
|
||
|
||
Calling a function is just like calling another program, you just
|
||
write its name.
|
||
|
||
|
||
8.1.
|
||
|
||
Functions sample
|
||
|
||
|
||
|
||
#!/bin/bash
|
||
function quit {
|
||
exit
|
||
}
|
||
function hello {
|
||
echo Hello!
|
||
}
|
||
hello
|
||
quit
|
||
echo foo
|
||
|
||
|
||
|
||
Lines 2-4 contain the 'quit' function. Lines 5-7 contain the 'hello'
|
||
function If you are not absolutely sure about what this script does,
|
||
please try it!.
|
||
|
||
Notice that a functions don't need to be declared in any specific
|
||
order.
|
||
|
||
When running the script you'll notice that first: the function 'hello'
|
||
is called, second the 'quit' function, and the program never reaches
|
||
line 10.
|
||
|
||
8.2.
|
||
|
||
Functions with parameters sample
|
||
|
||
|
||
|
||
#!/bin/bash
|
||
function quit {
|
||
exit
|
||
}
|
||
function e {
|
||
echo $1
|
||
}
|
||
e Hello
|
||
e World
|
||
quit
|
||
echo foo
|
||
|
||
|
||
|
||
This script is almost identically to the previous one. The main
|
||
difference is the funcion 'e'. This function, prints the first
|
||
argument it receives. Arguments, within funtions, are treated in the
|
||
same manner as arguments given to the script.
|
||
|
||
9.
|
||
|
||
|
||
User interfaces
|
||
|
||
9.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.
|
||
|
||
|
||
9.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.
|
||
|
||
10.
|
||
|
||
Misc
|
||
|
||
10.1.
|
||
|
||
Reading user input with read
|
||
|
||
In many ocations you may want to prompt the user for some input, and
|
||
there are several ways to achive 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 firstname and lastname
|
||
read FN LN
|
||
echo "Hi! $LN, $FN !"
|
||
|
||
|
||
|
||
10.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 math 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.
|
||
|
||
10.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.
|
||
|
||
|
||
|
||
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'.
|
||
|
||
10.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.5. Capturing a commands output
|
||
|
||
This little scripts show all tables from all databases (assuming you
|
||
got MySQL installed). Also, consider changing the 'mysql' command to
|
||
use a valid username and password.
|
||
|
||
|
||
#!/bin/bash
|
||
DBS=`mysql -uroot -e"show databases"`
|
||
for b in $DBS ;
|
||
do
|
||
mysql -uroot -e"show tables from $b"
|
||
done
|
||
|
||
|
||
|
||
10.6.
|
||
|
||
Multiple source files
|
||
|
||
You can use multiple files with the command source.
|
||
|
||
__TO-DO__
|
||
|
||
11.
|
||
|
||
|
||
Tables
|
||
11.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
|
||
|
||
11.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, refering 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.
|
||
|
||
|
||
11.3.
|
||
|
||
Arithmetic operators
|
||
|
||
+
|
||
|
||
-
|
||
|
||
*
|
||
|
||
/
|
||
|
||
% (remainder)
|
||
|
||
11.4.
|
||
|
||
Arithmetic relational operators
|
||
|
||
-lt (<)
|
||
|
||
-gt (>)
|
||
|
||
-le (<=)
|
||
|
||
-ge (>=)
|
||
|
||
-eq (==)
|
||
|
||
-ne (!=)
|
||
|
||
C programmer's should simple map the operator to its corresponding
|
||
parenthesis.
|
||
|
||
11.5.
|
||
|
||
Useful commands
|
||
|
||
This section was re-written by Kees (see thank to...)
|
||
|
||
Some of these command's almost contain complete programming languages.
|
||
From those commands only the basics will be explained. For a more
|
||
detailed description, have a closer look at the man pages of each
|
||
command.
|
||
|
||
sed (stream editor)
|
||
|
||
|
||
Sed is a non-interactive editor. Instead of altering a file by moving
|
||
the cursor on the screen, you use a script of editing instructions to
|
||
sed, plus the name of the file to edit. You can also describe sed as a
|
||
filter. Let's have a look at some examples:
|
||
|
||
|
||
|
||
$sed 's/to_be_replaced/replaced/g' /tmp/dummy
|
||
|
||
|
||
|
||
Sed replaces the string 'to_be_replaced' with the string 'replaced'
|
||
and reads from the /tmp/dummy file. The result will be sent to stdout
|
||
(normally the console) but you can also add '> capture' to the end of
|
||
the line above so that sed sends the output to the file 'capture'.
|
||
|
||
|
||
|
||
$sed 12, 18d /tmp/dummy
|
||
|
||
|
||
|
||
Sed shows all lines except lines 12 to 18. The original file is not
|
||
altered by this command.
|
||
|
||
awk (manipulation of datafiles, text retrieval and processing)
|
||
|
||
|
||
Many implementations of the AWK programming language exist (most known
|
||
interpreters are GNU's gawk and 'new awk' mawk.) The principle is
|
||
simple: AWK scans for a pattern, and for every matching pattern a
|
||
action will be performed.
|
||
|
||
Again, I've created a dummy file containing the following lines:
|
||
|
||
"test123
|
||
|
||
test
|
||
|
||
tteesstt"
|
||
|
||
|
||
|
||
$awk '/test/ {print}' /tmp/dummy
|
||
|
||
|
||
|
||
test123
|
||
|
||
|
||
test
|
||
|
||
|
||
The pattern AWK looks for is 'test' and the action it performs when it
|
||
found a line in the file /tmp/dummy with the string 'test' is 'print'.
|
||
|
||
|
||
|
||
$awk '/test/ {i=i+1} END {print i}' /tmp/dummy
|
||
|
||
|
||
|
||
3
|
||
|
||
|
||
When you're searching for many patterns, you should replace the text
|
||
between the quotes with '-f file.awk' so you can put all patterns and
|
||
actions in 'file.awk'.
|
||
|
||
grep (print lines matching a search pattern)
|
||
|
||
|
||
We've already seen quite a few grep commands in the previous chapters,
|
||
that display the lines matching a pattern. But grep can do more.
|
||
|
||
|
||
$grep "look for this" /var/log/messages -c
|
||
|
||
|
||
|
||
12
|
||
|
||
The string "look for this" has been found 12 times in the file
|
||
/var/log/messages.
|
||
|
||
|
||
[ok, this example was a fake, the /var/log/messages was tweaked :-)]
|
||
|
||
wc (counts lines, words and bytes)
|
||
|
||
|
||
In the following example, we see that the output is not what we
|
||
expected. The dummy file, as used in this example, contains the
|
||
following text: "bash introduction
|
||
howto test file"
|
||
|
||
|
||
|
||
$wc --words --lines --bytes /tmp/dummy
|
||
|
||
|
||
|
||
2 5 34 /tmp/dummy
|
||
|
||
|
||
Wc doesn't care about the parameter order. Wc always prints them in a
|
||
standard order, which is, as you can see: .
|
||
|
||
sort (sort lines of text files)
|
||
|
||
|
||
This time the dummy file contains the following text:
|
||
|
||
"b
|
||
|
||
c
|
||
|
||
a"
|
||
|
||
|
||
$sort /tmp/dummy
|
||
|
||
|
||
|
||
This is what the output looks like:
|
||
|
||
|
||
a
|
||
|
||
b
|
||
|
||
c
|
||
|
||
|
||
Commands shouldn't be that easy :-) bc (a calculator programming
|
||
language)
|
||
|
||
|
||
Bc is accepting calculations from command line (input from file. not
|
||
from redirector or pipe), but also from a user interface. The
|
||
following demonstration shows some of the commands. Note that
|
||
|
||
I start bc using the -q parameter to avoid a welcome message.
|
||
|
||
|
||
|
||
$bc -q
|
||
|
||
|
||
|
||
1 == 5
|
||
|
||
0
|
||
|
||
0.05 == 0.05
|
||
|
||
1
|
||
|
||
5 != 5
|
||
|
||
0
|
||
|
||
2 ^ 8
|
||
|
||
256
|
||
|
||
sqrt(9)
|
||
|
||
3
|
||
|
||
while (i != 9) {
|
||
|
||
i = i + 1;
|
||
|
||
print i
|
||
|
||
}
|
||
|
||
123456789
|
||
|
||
quit
|
||
|
||
tput (initialize a terminal or query terminfo database)
|
||
|
||
|
||
A little demonstration of tput's capabilities:
|
||
|
||
|
||
$tput cup 10 4
|
||
|
||
|
||
|
||
The prompt appears at (y10,x4).
|
||
|
||
|
||
$tput reset
|
||
|
||
|
||
|
||
Clears screen and prompt appears at (y1,x1). Note that (y0,x0) is the
|
||
upper left corner.
|
||
|
||
|
||
$tput cols
|
||
|
||
|
||
|
||
80
|
||
|
||
Shows the number of characters possible in x direction.
|
||
|
||
It it higly recommended to be familiarized with these programs (at
|
||
least). There are tons of little programs that will let you do real
|
||
magic on the command line.
|
||
|
||
[some samples are taken from man pages or FAQs]
|
||
|
||
12.
|
||
|
||
More Scripts
|
||
|
||
12.1. Applying a command to all files in a directory.
|
||
|
||
|
||
|
||
12.2.
|
||
|
||
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.3.
|
||
|
||
File re-namer
|
||
|
||
|
||
|
||
#!/bin/sh
|
||
# renna: rename multiple files according to several rules
|
||
# written by felix hudson Jan - 2000
|
||
|
||
#first check for the various 'modes' that this program has
|
||
#if the first ($1) condition matches then we execute that portion of the
|
||
#program and then exit
|
||
|
||
# check for the prefix condition
|
||
if [ $1 = p ]; then
|
||
|
||
#we now get rid of the mode ($1) variable and prefix ($2)
|
||
prefix=$2 ; shift ; shift
|
||
|
||
# a quick check to see if any files were given
|
||
# if none then its better not to do anything than rename some non-existent
|
||
# files!!
|
||
|
||
if [$1 = ]; then
|
||
echo "no files given"
|
||
exit 0
|
||
fi
|
||
|
||
# this for loop iterates through all of the files that we gave the program
|
||
# it does one rename per file given
|
||
for file in $*
|
||
do
|
||
mv ${file} $prefix$file
|
||
done
|
||
|
||
#we now exit the program
|
||
exit 0
|
||
fi
|
||
|
||
# check for a suffix rename
|
||
# the rest of this part is virtually identical to the previous section
|
||
# please see those notes
|
||
if [ $1 = s ]; then
|
||
suffix=$2 ; shift ; shift
|
||
|
||
if [$1 = ]; then
|
||
echo "no files given"
|
||
exit 0
|
||
fi
|
||
|
||
for file in $*
|
||
do
|
||
mv ${file} $file$suffix
|
||
done
|
||
|
||
exit 0
|
||
fi
|
||
|
||
# check for the replacement rename
|
||
if [ $1 = r ]; then
|
||
|
||
shift
|
||
|
||
# i included this bit as to not damage any files if the user does not specify
|
||
# anything to be done
|
||
# just a safety measure
|
||
|
||
if [ $# -lt 3 ] ; then
|
||
echo "usage: renna r [expression] [replacement] files... "
|
||
exit 0
|
||
fi
|
||
# remove other information
|
||
OLD=$1 ; NEW=$2 ; shift ; shift
|
||
|
||
# this for loop iterates through all of the files that we give the program
|
||
# it does one rename per file given using the program 'sed'
|
||
# this is a sinple command line program that parses standard input and
|
||
# replaces a set expression with a give string
|
||
# here we pass it the file name ( as standard input) and replace the nessesary
|
||
# text
|
||
|
||
for file in $*
|
||
do
|
||
new=`echo ${file} | sed s/${OLD}/${NEW}/g`
|
||
mv ${file} $new
|
||
done
|
||
exit 0
|
||
fi
|
||
|
||
# if we have reached here then nothing proper was passed to the program
|
||
# so we tell the user how to use it
|
||
echo "usage;"
|
||
echo " renna p [prefix] files.."
|
||
echo " renna s [suffix] files.."
|
||
echo " renna r [expression] [replacement] files.."
|
||
exit 0
|
||
|
||
# done!
|
||
|
||
|
||
|
||
12.4.
|
||
|
||
File renamer (simple)
|
||
|
||
|
||
|
||
#!/bin/bash
|
||
# renames.sh
|
||
# basic file renamer
|
||
|
||
criteria=$1
|
||
re_match=$2
|
||
replace=$3
|
||
|
||
for i in $( ls *$criteria* );
|
||
do
|
||
src=$i
|
||
tgt=$(echo $i | sed -e "s/$re_match/$replace/")
|
||
mv $src $tgt
|
||
done
|
||
|
||
|
||
|
||
13.
|
||
|
||
When something goes wrong (debugging)
|
||
|
||
13.1. Ways Calling BASH
|
||
|
||
A nice thing to do is to add on the first line
|
||
|
||
#!/bin/bash -x
|
||
|
||
|
||
|
||
This will produce some intresting output information
|
||
|
||
14.
|
||
|
||
About the document
|
||
|
||
Feel free to make suggestions/corrections, or whatever you think it
|
||
would be interesting to see in this document. I'll try to update it as
|
||
soon as I can.
|
||
|
||
14.1.
|
||
|
||
(no) warranty
|
||
|
||
This documents comes with no warranty of any kind. and all that
|
||
|
||
14.2.
|
||
|
||
Translations
|
||
|
||
Italian: by William Ghelfi (wizzy at tiscalinet.it) is here
|
||
|
||
French: by Laurent Martelli is missed
|
||
|
||
Korean: Minseok Park http://kldp.org
|
||
|
||
Korean: Chun Hye Jin unknown
|
||
|
||
Spanish: unknow http://www.insflug.org
|
||
|
||
I guess there are more translations, but I don't have any info of
|
||
them, if you have it, please, mail it to me so I update this section.
|
||
|
||
14.3.
|
||
|
||
Thanks to
|
||
|
||
|
||
· People who translated this document to other languages (previous
|
||
section).
|
||
|
||
· Nathan Hurst for sending a lot of corrections.
|
||
|
||
· Jon Abbott for sending comments about evaluating arithmetic
|
||
expressions.
|
||
|
||
· Felix Hudson for writing the renna script
|
||
|
||
· Kees van den Broek (for sending many corrections, re-writting
|
||
usefull comands section)
|
||
|
||
· Mike (pink) made some suggestions about locating bash and testing
|
||
files
|
||
|
||
· Fiesh make a nice suggestion for the loops section.
|
||
|
||
· Lion suggested to mention a common error (./hello.sh: Command not
|
||
found.)
|
||
|
||
|
||
· Andreas Beck made several corrections and coments.
|
||
|
||
14.4.
|
||
|
||
History
|
||
|
||
New translations included and minor correcitons.
|
||
|
||
Added the section usefull commands re-writen by Kess.
|
||
|
||
More corrections and suggestions incorporated.
|
||
|
||
Samples added on string comparison.
|
||
|
||
v0.8 droped the versioning, I guess the date is enought.
|
||
|
||
v0.7 More corrections and some old TO-DO sections written.
|
||
|
||
v0.6 Minor corrections.
|
||
|
||
v0.5 Added the redirection section.
|
||
|
||
v0.4 disapperd from its location due to my ex-boss and thid doc found
|
||
it's new place at the proper url: www.linuxdoc.org.
|
||
|
||
prior: I don't rememeber and I didn't use rcs nor cvs :(
|
||
|
||
14.5.
|
||
|
||
More resources
|
||
|
||
|
||
Introduction to bash (under BE)
|
||
http://org.laol.net/lamug/beforever/bashtut.htm
|
||
|
||
Bourne Shell Programming http://207.213.123.70/book/
|
||
|
||
|
||
|