2000-06-12 18:09:51 +00:00
|
|
|
<!doctype linuxdoc system>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!--
|
2000-06-12 18:09:51 +00:00
|
|
|
An introduction to bash shell programming
|
|
|
|
-->
|
|
|
|
|
|
|
|
<!-- Title information -->
|
|
|
|
|
|
|
|
<article>
|
|
|
|
<title>BASH Programming - Introduction HOW-TO</title>
|
2000-07-27 13:51:54 +00:00
|
|
|
<author>by Mike G <tt/mikkey at dynamo.com.ar/</author>
|
2016-02-09 22:09:35 +00:00
|
|
|
<date>
|
2000-07-27 13:51:54 +00:00
|
|
|
Thu Jul 27 09:36:18 ART 2000
|
|
|
|
</date>
|
2016-02-09 22:09:35 +00:00
|
|
|
<abstract>
|
|
|
|
This article is intended to help you to start programming
|
|
|
|
basic-intermediate shell scripts. It does not intend to be an
|
|
|
|
advanced document (see the title). I am NOT an expert nor guru
|
|
|
|
shell programmer. I decided to write this because I'll learn a
|
2016-02-12 18:56:21 +00:00
|
|
|
lot and it might be useful to other people. Any feedback is
|
2016-02-09 22:09:35 +00:00
|
|
|
appreciated, especially in the patch or pull request form. :)
|
2000-06-12 18:09:51 +00:00
|
|
|
</abstract>
|
|
|
|
|
|
|
|
<!-- Table of contents -->
|
|
|
|
<toc>
|
|
|
|
|
|
|
|
<!-- Requisites -->
|
|
|
|
<sect>
|
|
|
|
Introduction
|
2000-06-20 14:41:52 +00:00
|
|
|
|
2000-06-22 18:54:39 +00:00
|
|
|
|
2000-07-05 17:23:44 +00:00
|
|
|
<sect1>
|
|
|
|
Getting the latest version
|
2000-06-12 18:09:51 +00:00
|
|
|
|
2000-07-05 17:23:44 +00:00
|
|
|
<p>
|
2019-04-01 16:22:16 +00:00
|
|
|
<htmlurl url="https://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html"
|
|
|
|
name="https://www.tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">
|
2000-06-12 18:09:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
</sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Requisites
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> Familiarity with GNU/Linux command lines, and familiarity
|
2000-06-12 18:09:51 +00:00
|
|
|
with basic programming concepts is helpful. While this is not
|
|
|
|
a programming introduction, it explains (or at least tries) many
|
|
|
|
basic concepts.
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
Uses of this document
|
|
|
|
<P> This document tries to be useful in the following situations
|
|
|
|
<itemize>
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> You have an idea about programming and you want to start
|
2000-06-12 18:09:51 +00:00
|
|
|
coding some shell scripts.
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> You have a vague idea about shell programming and want
|
2000-06-12 18:09:51 +00:00
|
|
|
some sort of reference.
|
|
|
|
<item> You want to see some shell scripts and some comments to
|
2016-02-09 22:09:35 +00:00
|
|
|
start writing your own.
|
|
|
|
<item> You are migrating from DOS/Windows (or already did)
|
2000-06-12 18:09:51 +00:00
|
|
|
and want to make "batch" processes.
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> You are a complete nerd and read every how-to available.
|
2000-06-12 18:09:51 +00:00
|
|
|
</itemize>
|
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Very simple Scripts -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect>
|
|
|
|
Very simple Scripts
|
|
|
|
|
|
|
|
<P> This HOW-TO will try to give you some hints about shell script
|
|
|
|
programming strongly based on examples.
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> In this section you'll find some little scripts which
|
2000-06-12 18:09:51 +00:00
|
|
|
will hopefully help you to understand some techniques.
|
|
|
|
|
|
|
|
<sect1>
|
|
|
|
Traditional hello world script
|
|
|
|
|
|
|
|
<!-- __TO-DO__
|
2016-02-09 22:09:35 +00:00
|
|
|
someone suggested using this instead of the line numbering
|
2000-06-12 18:09:51 +00:00
|
|
|
but it doesn't work on verion 1.0.9
|
2016-02-09 22:09:35 +00:00
|
|
|
<pre></pre>
|
2000-06-12 18:09:51 +00:00
|
|
|
-->
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
|
|
|
echo Hello World
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
|
|
|
<P> This script has only two lines.
|
|
|
|
The first indicates the system which program
|
|
|
|
to use to run the file.
|
|
|
|
<P> The second line is the only action performed by this script,
|
2000-06-22 18:54:39 +00:00
|
|
|
which prints 'Hello World' on the terminal.
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> If you get something like <it>./hello.sh: Command not found.</it>
|
2016-02-09 22:09:35 +00:00
|
|
|
Probably the first line '#!/bin/bash' is wrong, issue whereis bash or see
|
|
|
|
'finding bash' to see how should you write this line.
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
A very simple backup script
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2022-01-21 07:41:46 +00:00
|
|
|
tar -czf /var/my-backup.tgz /home/me/
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> In this script, instead of printing a message on the terminal,
|
2000-06-12 18:09:51 +00:00
|
|
|
we create a tar-ball of a user's home directory. This is NOT intended
|
2016-02-09 22:09:35 +00:00
|
|
|
to be used, a more useful backup script is presented later in this
|
2000-06-12 18:09:51 +00:00
|
|
|
document.
|
2016-02-09 22:09:35 +00:00
|
|
|
</sect1>
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect>
|
|
|
|
|
2000-06-20 14:41:52 +00:00
|
|
|
<!-- Redirection -->
|
|
|
|
<sect>
|
|
|
|
All about redirection
|
|
|
|
|
|
|
|
<sect1>
|
|
|
|
Theory and quick reference
|
2000-06-22 18:54:39 +00:00
|
|
|
<p> There are 3 file descriptors, stdin, stdout and stderr (std=standard).
|
2000-06-20 14:41:52 +00:00
|
|
|
|
|
|
|
<p>Basically you can:
|
|
|
|
<enum>
|
|
|
|
<item> redirect stdout to a file
|
|
|
|
<item> redirect stderr to a file
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> redirect stdout to a stderr
|
|
|
|
<item> redirect stderr to a stdout
|
|
|
|
<item> redirect stderr and stdout to a file
|
|
|
|
<item> redirect stderr and stdout to stdout
|
2000-06-20 14:41:52 +00:00
|
|
|
<item> redirect stderr and stdout to stderr
|
|
|
|
</enum>
|
2000-06-22 18:54:39 +00:00
|
|
|
1 'represents' stdout and 2 stderr.
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> A little note for seeing the output of these commands: 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.
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-20 14:41:52 +00:00
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: stdout 2 file
|
|
|
|
<p> This will cause the output of a program to be written to a file.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
ls -l > ls-l.txt
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
Here, a file called 'ls-l.txt' will be created and it will contain what you would see on the
|
2000-06-20 14:41:52 +00:00
|
|
|
screen if you type the command 'ls -l' and execute it.
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: stderr 2 file
|
|
|
|
<p> This will cause the stderr output of a program to be written to a file.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
grep da * 2> grep-errors.txt
|
|
|
|
</verb></tscreen>
|
|
|
|
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.
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1>
|
|
|
|
Sample: stdout 2 stderr
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> This will cause the stdout output of a program to be written to the same filedescriptor
|
2016-01-19 14:49:58 +00:00
|
|
|
as stderr.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
grep da * 1>&2
|
2000-06-20 14:41:52 +00:00
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
Here, the stdout portion of the command is sent to stderr, you may notice that in different ways.
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: stderr 2 stdout
|
|
|
|
<p> This will cause the stderr output of a program to be written to the same filedescriptor
|
2016-01-19 14:49:58 +00:00
|
|
|
as stdout.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
grep * 2>&1
|
|
|
|
</verb></tscreen>
|
|
|
|
Here, the stderr portion of the command is sent to stdout, if you pipe to less, you'll see that
|
2016-02-09 22:09:35 +00:00
|
|
|
lines that normally 'disappear' (as they are written to stderr) are being kept now (because
|
|
|
|
they're on stdout).
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: stderr and stdout 2 file
|
|
|
|
<p> 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.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
rm -f $(find / -name core) &> /dev/null
|
2000-06-20 14:41:52 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
This (thinking on the cron entry) will delete every file called 'core' in any directory. Notice
|
2019-04-01 16:21:10 +00:00
|
|
|
that you should be pretty sure of what a command is doing if you are going to wipe its output.
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
|
|
|
<!--
|
2016-02-09 22:09:35 +00:00
|
|
|
redirect stderr and stdout to stdout
|
2000-06-20 14:41:52 +00:00
|
|
|
redirect stderr and stdout to stderr
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample:
|
|
|
|
<p> This will
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
command
|
|
|
|
</verb></tscreen>
|
|
|
|
Explanation
|
|
|
|
</sect1>
|
|
|
|
-->
|
|
|
|
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
<!-- pipes -->
|
|
|
|
<sect>
|
|
|
|
Pipes
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> This section explains in a very simple and practical way how to use pipes,
|
|
|
|
and why you may want to use them.
|
2000-06-20 14:41:52 +00:00
|
|
|
|
|
|
|
<sect1>
|
|
|
|
What they are and why you'll want to use them
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Pipes let you use (very simple, I insist) the output of a program as the
|
|
|
|
input of another one
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: simple pipe with sed
|
2000-06-20 14:41:52 +00:00
|
|
|
<p> This is very simple way to use pipes.
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
ls -l | sed -e "s/[aeio]/u/g"
|
2000-06-20 14:41:52 +00:00
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
Here, the following happens: first the command ls -l is executed, and its output,
|
2000-06-20 14:41:52 +00:00
|
|
|
instead of being printed, is sent (piped) to the sed program, which in turn, prints
|
2016-02-09 22:09:35 +00:00
|
|
|
what it has to.
|
2000-06-20 14:41:52 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: an alternative to ls -l *.txt
|
2000-06-20 14:41:52 +00:00
|
|
|
<p> Probably, this is a more difficult way to do ls -l *.txt, but it is here for illustrating pipes,
|
2016-02-12 18:56:21 +00:00
|
|
|
not for solving such listing dilemma.
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
ls -l | grep "\.txt$"
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
Here, the output of the program ls -l is sent to the grep program, which, in turn, will print
|
2000-06-20 14:41:52 +00:00
|
|
|
lines which match the regex "\.txt$".
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample:
|
|
|
|
<p> This will
|
2000-06-20 14:41:52 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
command
|
|
|
|
</verb></tscreen>
|
|
|
|
Explanation
|
|
|
|
</sect1>
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<!-- Variables -->
|
|
|
|
<sect>
|
|
|
|
Variables
|
|
|
|
|
|
|
|
<!-- Dry Theory -->
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> You can use variables as in any programming languages.
|
2000-06-12 18:09:51 +00:00
|
|
|
There are no data types. A variable in bash can contain a number, a
|
2016-02-09 22:09:35 +00:00
|
|
|
character, a string of characters.
|
|
|
|
<P> You have no need to declare a variable, just
|
2000-06-12 18:09:51 +00:00
|
|
|
assigning a value to its reference will create it.
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
|
|
|
|
<!-- Samples -->
|
|
|
|
<sect1>
|
|
|
|
Sample: Hello World! using variables
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-12 18:09:51 +00:00
|
|
|
STR="Hello World!"
|
2016-02-09 22:09:35 +00:00
|
|
|
echo $STR
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> Line 2 creates
|
2000-06-12 18:09:51 +00:00
|
|
|
a variable called STR and assigns the string "Hello World!" to
|
2016-02-09 22:09:35 +00:00
|
|
|
it. Then the VALUE of this variable is retrieved by putting
|
|
|
|
the '$' in at the beginning. Please notice (try it!)
|
2000-06-12 18:09:51 +00:00
|
|
|
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.
|
|
|
|
</sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Sample: A very simple backup script (little bit better)
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-12 18:09:51 +00:00
|
|
|
OF=/var/my-backup-$(date +%Y%m%d).tgz
|
2022-01-21 07:41:46 +00:00
|
|
|
tar -czf $OF /home/me/
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> This script introduces another thing. First
|
|
|
|
of all, you should be familiarized with the variable
|
2000-06-12 18:09:51 +00:00
|
|
|
creation and assignation on line 2. Notice the expression
|
|
|
|
'$(date +%Y%m%d)'.
|
2016-02-09 22:09:35 +00:00
|
|
|
If you run the script you'll notice that
|
2000-06-12 18:09:51 +00:00
|
|
|
it runs the
|
2016-02-09 22:09:35 +00:00
|
|
|
command inside the parenthesis, capturing its output.
|
2000-06-12 18:09:51 +00:00
|
|
|
|
|
|
|
<P> Notice that in this script, the output filename will
|
2000-06-22 18:54:39 +00:00
|
|
|
be different every day, due to the format switch to the date command(+%Y%m%d).
|
2000-06-12 18:09:51 +00:00
|
|
|
You can change this by specifying a different format.
|
|
|
|
<P> Some more examples:
|
|
|
|
<P> echo ls
|
|
|
|
<P> echo $(ls)
|
2016-02-09 22:09:35 +00:00
|
|
|
</sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
|
|
|
|
<sect1>
|
|
|
|
Local variables
|
|
|
|
|
|
|
|
<p> Local variables can be created by using the keyword <it/local/.
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
2016-02-09 22:09:35 +00:00
|
|
|
HELLO=Hello
|
2000-06-22 18:54:39 +00:00
|
|
|
function hello {
|
|
|
|
local HELLO=World
|
|
|
|
echo $HELLO
|
|
|
|
}
|
|
|
|
echo $HELLO
|
|
|
|
hello
|
|
|
|
echo $HELLO
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> This example should be enought to show how to use a local variable.
|
2000-06-22 18:54:39 +00:00
|
|
|
</sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect>
|
|
|
|
|
|
|
|
<!-- Conditionals -->
|
|
|
|
<sect>
|
|
|
|
Conditionals
|
2016-02-09 22:09:35 +00:00
|
|
|
|
|
|
|
<P> Conditionals let you decide whether to perform an action
|
2000-06-12 18:09:51 +00:00
|
|
|
or not, this decision is taken by evaluating an expression.
|
|
|
|
|
|
|
|
<!-- Dry Theory -->
|
|
|
|
<sect1>
|
|
|
|
Dry Theory
|
|
|
|
<P> Conditionals have many forms. The most basic form is:
|
2000-07-18 14:15:50 +00:00
|
|
|
<bf>if</bf> <it/expression/ <bf>then</bf> <it/statement/
|
2016-02-09 22:09:35 +00:00
|
|
|
where 'statement' is only executed if 'expression'
|
2000-06-12 18:09:51 +00:00
|
|
|
evaluates to true.
|
2016-02-09 22:09:35 +00:00
|
|
|
'2<1' is an expresion that evaluates to false, while '2>1'
|
2000-06-12 18:09:51 +00:00
|
|
|
evaluates to true.xs
|
2000-07-18 14:15:50 +00:00
|
|
|
<p> Conditionals have other forms such as:
|
2016-02-09 22:09:35 +00:00
|
|
|
<bf/if/ <it/expression/
|
2000-06-12 18:09:51 +00:00
|
|
|
<bf/then/ <it/statement1/ <bf/else/ <it/statement2/.
|
|
|
|
Here 'statement1' is executed if 'expression' is true,otherwise
|
|
|
|
'statement2' is executed.
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> Yet another form of conditionals is:
|
|
|
|
<bf/if/ <it/expression1/
|
|
|
|
<bf/then/ <it/statement1/
|
|
|
|
<bf/else if/ <it/expression2/ <bf/then/ <it/statement2/
|
2000-06-12 18:09:51 +00:00
|
|
|
<bf/else/ <it/statement3/.
|
|
|
|
In this form there's added only the
|
|
|
|
"ELSE IF 'expression2' THEN 'statement2'" which makes statement2 being
|
2016-02-09 22:09:35 +00:00
|
|
|
executed if expression2 evaluates to true. The rest is as you may
|
2000-06-12 18:09:51 +00:00
|
|
|
imagine (see previous forms).
|
|
|
|
<P> A word about syntax:
|
|
|
|
<P> The base for the 'if' constructions in bash is this:
|
|
|
|
<P> if [expression];
|
|
|
|
<P> then
|
|
|
|
<P> code if 'expression' is true.
|
|
|
|
<P> fi
|
|
|
|
</sect1>
|
|
|
|
<!-- Samples -->
|
|
|
|
<sect1>
|
|
|
|
Sample: Basic conditional example if .. then
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
if [ "foo" = "foo" ]; then
|
|
|
|
echo expression evaluated as true
|
|
|
|
fi
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> 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
|
2000-06-12 18:09:51 +00:00
|
|
|
of the conditionally executed code.
|
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
Sample: Basic conditional example if .. then ... else
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
if [ "foo" = "foo" ]; then
|
|
|
|
echo expression evaluated as true
|
|
|
|
else
|
|
|
|
echo expression evaluated as false
|
|
|
|
fi
|
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
Sample: Conditionals with variables
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
T1="foo"
|
|
|
|
T2="bar"
|
2000-07-05 17:23:44 +00:00
|
|
|
if [ "$T1" = "$T2" ]; then
|
2000-06-12 18:09:51 +00:00
|
|
|
echo expression evaluated as true
|
|
|
|
else
|
|
|
|
echo expression evaluated as false
|
|
|
|
fi
|
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
2000-06-21 17:28:14 +00:00
|
|
|
<!--
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Sample: testing if a file exists
|
|
|
|
<P> one more thank to mike
|
2000-06-21 17:28:14 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
FILE=~/.basrc
|
|
|
|
if [ -f $FILE ]; then
|
|
|
|
echo file $FILE exits
|
|
|
|
else
|
|
|
|
echo file not found
|
|
|
|
fi
|
|
|
|
if [ 'test -f $FILE']
|
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
|
|
|
-->
|
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect>
|
|
|
|
|
|
|
|
<!-- Loops : for, while and until -->
|
|
|
|
<sect>
|
|
|
|
Loops for, while and until
|
|
|
|
<!-- Dry Theory -->
|
|
|
|
|
|
|
|
<P> In this section you'll find for, while and until loops.
|
|
|
|
<P> The <bf/for/ loop is a little bit different from other programming
|
2016-02-09 22:09:35 +00:00
|
|
|
languages. Basically, it let's you iterate over a series of
|
2000-06-12 18:09:51 +00:00
|
|
|
'words' within a string.
|
|
|
|
<P> The <bf/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.
|
|
|
|
<P> The <bf/until/ loop is almost equal to the while loop, except that
|
|
|
|
the code is executed while the control expression evaluates to false.
|
|
|
|
<P> If you suspect that while and until are very similar you are right.
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Samples -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
For sample
|
2016-02-09 22:09:35 +00:00
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
for i in $( ls ); do
|
|
|
|
echo item: $i
|
|
|
|
done
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<p>
|
2000-06-12 18:09:51 +00:00
|
|
|
<p> On the second line, we declare i to be the variable that
|
2016-02-09 22:09:35 +00:00
|
|
|
will take the
|
2000-06-12 18:09:51 +00:00
|
|
|
different values contained in $( ls ).
|
|
|
|
<p> The third line could be longer if needed, or there could
|
2016-02-09 22:09:35 +00:00
|
|
|
be more lines
|
2000-06-12 18:09:51 +00:00
|
|
|
before the done (4).
|
|
|
|
<p> 'done' (4) indicates that the code that used the value of $i has
|
|
|
|
finished and $i can take a new value.
|
|
|
|
<p> 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
|
|
|
|
<p>
|
|
|
|
</sect1>
|
2000-06-23 20:17:41 +00:00
|
|
|
<sect1>
|
|
|
|
C-like for
|
|
|
|
<P> fiesh suggested adding this form of looping. It's a for loop
|
|
|
|
more similar to C/perl... for.
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
for i in `seq 1 10`;
|
|
|
|
do
|
|
|
|
echo $i
|
2016-02-09 22:09:35 +00:00
|
|
|
done
|
2000-06-23 20:17:41 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
2000-06-12 18:09:51 +00:00
|
|
|
<!-- while -->
|
|
|
|
<sect1>
|
|
|
|
While sample
|
|
|
|
<P> <tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-12 18:09:51 +00:00
|
|
|
COUNTER=0
|
|
|
|
while [ $COUNTER -lt 10 ]; do
|
|
|
|
echo The counter is $COUNTER
|
2016-02-09 22:09:35 +00:00
|
|
|
let COUNTER=COUNTER+1
|
2000-06-12 18:09:51 +00:00
|
|
|
done
|
|
|
|
</verb></tscreen>
|
|
|
|
<P>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> This script 'emulates' the well known
|
2000-07-05 17:23:44 +00:00
|
|
|
(C, Pascal, perl, etc) 'for' structure
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
<!-- until -->
|
|
|
|
<sect1>
|
|
|
|
Until sample
|
|
|
|
<P> <tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-12 18:09:51 +00:00
|
|
|
COUNTER=20
|
|
|
|
until [ $COUNTER -lt 10 ]; do
|
|
|
|
echo COUNTER $COUNTER
|
|
|
|
let COUNTER-=1
|
|
|
|
done
|
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
<!-- Functions -->
|
|
|
|
<sect>
|
|
|
|
Functions
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> As in almost any programming language, you can use functions to group
|
2000-06-12 18:09:51 +00:00
|
|
|
pieces of code in a more logical way or practice the divine art of recursion.
|
|
|
|
<P> Declaring a function is just a matter of writing function my_func { my_code }.
|
|
|
|
<P> Calling a function is just like calling another program, you just write its name.
|
|
|
|
<P>
|
|
|
|
<sect1>
|
|
|
|
Functions sample
|
|
|
|
<P> <tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-22 18:54:39 +00:00
|
|
|
function quit {
|
|
|
|
exit
|
|
|
|
}
|
|
|
|
function hello {
|
|
|
|
echo Hello!
|
|
|
|
}
|
|
|
|
hello
|
|
|
|
quit
|
2016-02-09 22:09:35 +00:00
|
|
|
echo foo
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
<P> Lines 2-4 contain the 'quit' function. Lines 5-7 contain the 'hello' function
|
2019-08-27 16:18:23 +00:00
|
|
|
If you are not absolutely sure about what this script does, please try it!
|
2016-03-31 19:42:04 +00:00
|
|
|
<P> Notice that functions don't need to be declared in any specific order.
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> When running the script you'll notice that first: the function 'hello' is
|
2000-06-12 18:09:51 +00:00
|
|
|
called, second the 'quit' function, and the program never reaches line 10.
|
|
|
|
</sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
|
|
|
|
<sect1>
|
|
|
|
Functions with parameters sample
|
|
|
|
<P> <tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-22 18:54:39 +00:00
|
|
|
function quit {
|
|
|
|
exit
|
2016-02-09 22:09:35 +00:00
|
|
|
}
|
2000-06-22 18:54:39 +00:00
|
|
|
function e {
|
2016-02-09 22:09:35 +00:00
|
|
|
echo $1
|
|
|
|
}
|
2000-06-22 18:54:39 +00:00
|
|
|
e Hello
|
|
|
|
e World
|
|
|
|
quit
|
2016-02-09 22:09:35 +00:00
|
|
|
echo foo
|
2000-06-22 18:54:39 +00:00
|
|
|
|
|
|
|
</verb></tscreen>
|
2019-10-31 02:22:40 +00:00
|
|
|
<P> This script is almost identical to the previous one. The main difference is the
|
|
|
|
function 'e'. This function, prints the first argument it receives.
|
|
|
|
Arguments, within functions, are treated in the same manner as arguments given to the script.
|
2000-06-22 18:54:39 +00:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- User interfaces -->
|
|
|
|
<sect>
|
|
|
|
User interfaces
|
|
|
|
<!-- Simple menus with select -->
|
|
|
|
<sect1>
|
|
|
|
Using select to make simple menus
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
OPTIONS="Hello Quit"
|
|
|
|
select opt in $OPTIONS; do
|
2000-07-05 17:23:44 +00:00
|
|
|
if [ "$opt" = "Quit" ]; then
|
2000-06-12 18:09:51 +00:00
|
|
|
echo done
|
|
|
|
exit
|
2000-07-05 17:23:44 +00:00
|
|
|
elif [ "$opt" = "Hello" ]; then
|
2000-06-12 18:09:51 +00:00
|
|
|
echo Hello World
|
|
|
|
else
|
|
|
|
clear
|
|
|
|
echo bad option
|
|
|
|
fi
|
|
|
|
done
|
2016-02-09 22:09:35 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
<P> 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
|
2000-06-12 18:09:51 +00:00
|
|
|
than looping for each 'word' in $OPTIONS, it prompts the user.
|
|
|
|
<P>
|
|
|
|
</sect1>
|
|
|
|
<!-- Using the command line -->
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Using the command line
|
2000-06-12 18:09:51 +00:00
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
|
|
|
if [ -z "$1" ]; then
|
2000-06-12 18:09:51 +00:00
|
|
|
echo usage: $0 directory
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
SRCD=$1
|
|
|
|
TGTD="/var/backups/"
|
|
|
|
OF=home-$(date +%Y%m%d).tgz
|
2022-01-21 07:41:46 +00:00
|
|
|
tar -czf $TGTD$OF $SRCD
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
<P>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> What this script does should be clear to you. The expression
|
2000-06-12 18:09:51 +00:00
|
|
|
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.
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
<!-- Misc -->
|
|
|
|
<sect>
|
|
|
|
Misc
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Reading user input -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
Reading user input with read
|
2016-04-01 14:08:22 +00:00
|
|
|
<P> In many occasions you may want to prompt the user for some input, and
|
2016-02-09 22:09:35 +00:00
|
|
|
there are several ways
|
2000-06-22 18:54:39 +00:00
|
|
|
to achive this. This is one of those ways:
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
echo Please, enter your name
|
|
|
|
read NAME
|
|
|
|
echo "Hi $NAME!"
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> As a variant, you can get multiple values with read, this example may
|
2000-07-05 17:23:44 +00:00
|
|
|
clarify this.
|
2000-06-22 18:54:39 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
echo Please, enter your firstname and lastname
|
2016-02-09 22:09:35 +00:00
|
|
|
read FN LN
|
2000-06-22 18:54:39 +00:00
|
|
|
echo "Hi! $LN, $FN !"
|
|
|
|
</verb></tscreen>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Arithmetic evaluation -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Arithmetic evaluation
|
|
|
|
<P> On the command line (or a shell) try this:
|
|
|
|
<P> echo 1 + 1
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> If you expected to see '2' you'll be disappointed. What if
|
2000-06-12 18:09:51 +00:00
|
|
|
you want BASH to evaluate some numbers you have? The solution
|
|
|
|
is this:
|
|
|
|
<P> echo $((1+1))
|
|
|
|
<P> This will produce a more 'logical' output. This is to evaluate an
|
|
|
|
arithmetic expression. You can achieve this also like this:
|
|
|
|
<P> echo $[1+1]
|
|
|
|
<P>
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> If you need to use fractions, or more math or you just want it, you
|
2000-06-12 18:09:51 +00:00
|
|
|
can use bc to evaluate arithmetic expressions.
|
2016-04-01 14:14:31 +00:00
|
|
|
<P> If I ran "echo $[3/4]" at the command prompt, it would return 0
|
2000-06-12 18:09:51 +00:00
|
|
|
because bash only uses integers when answering. If you ran
|
|
|
|
"echo 3/4|bc -l", it would properly return 0.75.
|
|
|
|
</sect1>
|
|
|
|
|
2000-06-21 17:28:14 +00:00
|
|
|
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Finding bash
|
|
|
|
<P> From a message from mike (see Thanks to)
|
2000-06-23 20:17:41 +00:00
|
|
|
<P> you always use #!/bin/bash .. you might was to give an example of
|
|
|
|
<P> how to find where bash is located.
|
|
|
|
<P> 'locate bash' is preferred, but not all machines have locate.
|
|
|
|
<P> 'find ./ -name bash' from the root dir will work, usually.
|
|
|
|
<P> Suggested locations to check:
|
|
|
|
<P> ls -l /bin/bash
|
|
|
|
<P> ls -l /sbin/bash
|
|
|
|
<P> ls -l /usr/local/bin/bash
|
|
|
|
<P> ls -l /usr/bin/bash
|
|
|
|
<P> ls -l /usr/sbin/bash
|
|
|
|
<P> ls -l /usr/local/sbin/bash
|
|
|
|
<P> (can't think of any other dirs offhand... i've found it in
|
|
|
|
<P> most of these places before on different system).
|
2000-07-18 14:15:50 +00:00
|
|
|
<P> You may try also 'which bash'.
|
2000-06-21 17:28:14 +00:00
|
|
|
</sect1>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Capturing a commands output -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
2000-06-21 17:28:14 +00:00
|
|
|
Getting the return value of a program
|
|
|
|
<P> In bash, the return value of a program is stored in a special variable called $?.
|
|
|
|
<P> This illustrates how to capture the return value of a program, I assume that the directory
|
2000-06-22 18:54:39 +00:00
|
|
|
<it/dada/ does not exist. (This was also suggested by mike)
|
2000-06-21 17:28:14 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
cd /dada &> /dev/null
|
|
|
|
echo rv: $?
|
|
|
|
cd $(pwd) &> /dev/null
|
|
|
|
echo rv: $?
|
|
|
|
</verb> </tscreen>
|
|
|
|
</sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
<!-- Capturing a commands output -->
|
2000-06-21 17:28:14 +00:00
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Capturing a commands output
|
2016-04-01 14:21:18 +00:00
|
|
|
<P> This little script shows all tables from all databases (assuming you got MySQL installed).
|
2000-06-21 17:28:14 +00:00
|
|
|
Also, consider changing the 'mysql' command to use a valid username and password.
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
DBS=`mysql -uroot -e"show databases"`
|
|
|
|
for b in $DBS ;
|
|
|
|
do
|
|
|
|
mysql -uroot -e"show tables from $b"
|
|
|
|
done
|
|
|
|
</verb></tscreen>
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<!-- Multiple source files -->
|
|
|
|
<sect1>
|
|
|
|
Multiple source files
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> You can use multiple files with the command source.
|
2000-06-21 17:28:14 +00:00
|
|
|
<P> __TO-DO__
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Tables -->
|
|
|
|
<sect>
|
|
|
|
Tables
|
|
|
|
<!-- String operators -->
|
|
|
|
<sect1>
|
|
|
|
String comparison operators
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<P> (1) s1 = s2
|
|
|
|
<P> (2) s1 != s2
|
|
|
|
<P> (3) s1 < s2
|
|
|
|
<P> (4) s1 > s2
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> (5) -n s1
|
|
|
|
<P> (6) -z s1
|
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
<P> (1) s1 matches s2
|
|
|
|
<P> (2) s1 does not match s2
|
|
|
|
<P> (3) __TO-DO__
|
|
|
|
<P> (4) __TO-DO__
|
|
|
|
<P> (5) s1 is not null (contains one or more characters)
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> (6) s1 is null
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
2000-06-22 18:54:39 +00:00
|
|
|
|
|
|
|
<sect1>
|
|
|
|
String comparison examples
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Comparing two strings.
|
2000-06-22 18:54:39 +00:00
|
|
|
<tscreen><verb>
|
|
|
|
#!/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
|
|
|
|
</verb></tscreen>
|
2000-07-05 17:23:44 +00:00
|
|
|
<p> I quote here a note from a mail, sent buy Andreas Beck, refering to use
|
|
|
|
<it/if [ $1 = $2 ]/.
|
|
|
|
<p> 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.
|
|
|
|
|
2000-06-22 18:54:39 +00:00
|
|
|
</sect1>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Arithmetic operators -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Arithmetic operators
|
|
|
|
<P> +
|
|
|
|
<P> -
|
|
|
|
<P> *
|
|
|
|
<P> /
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> % (remainder)
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<!-- Arithmetic relational operators -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Arithmetic relational operators
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> -lt (<)
|
2000-06-12 18:09:51 +00:00
|
|
|
<P> -gt (>)
|
|
|
|
<P> -le (<=)
|
|
|
|
<P> -ge (>=)
|
|
|
|
<P> -eq (==)
|
|
|
|
<P> -ne (!=)
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> C programmer's should simple map the operator to its corresponding
|
2000-06-12 18:09:51 +00:00
|
|
|
parenthesis.
|
|
|
|
</sect1>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
|
|
|
|
<!-- Useful commands -->
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
Useful commands
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> This section was re-written by Kees (see thank to...)
|
2016-04-01 14:35:11 +00:00
|
|
|
<P> Some of these commands almost contain complete programming languages.
|
2016-02-09 22:09:35 +00:00
|
|
|
From those commands only the basics will be explained. For a more detailed
|
2016-04-01 14:36:47 +00:00
|
|
|
description, have a closer look at the main pages of each command.
|
2000-07-05 17:23:44 +00:00
|
|
|
|
|
|
|
<bf/sed/ (stream editor)
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> 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
|
2000-07-05 17:23:44 +00:00
|
|
|
a look at some examples:
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$sed 's/to_be_replaced/replaced/g' /tmp/dummy
|
|
|
|
</verb></tscreen>
|
|
|
|
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> 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
|
2000-07-05 17:23:44 +00:00
|
|
|
that sed sends the output to the file 'capture'.
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$sed 12, 18d /tmp/dummy
|
2016-02-09 22:09:35 +00:00
|
|
|
</verb></tscreen>
|
2000-07-05 17:23:44 +00:00
|
|
|
|
|
|
|
<P> Sed shows all lines except lines 12 to 18. The original file is not altered by this command.
|
|
|
|
|
|
|
|
<bf/awk/ (manipulation of datafiles, text retrieval and processing)
|
|
|
|
|
|
|
|
<P> 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
|
2016-04-01 14:42:03 +00:00
|
|
|
matching pattern an action will be performed.
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> Again, I've created a dummy file containing the following lines:
|
|
|
|
<P> <it/"test123/
|
|
|
|
<P> <it/test/
|
|
|
|
<P> <it/tteesstt"/
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$awk '/test/ {print}' /tmp/dummy
|
|
|
|
</verb></tscreen>
|
|
|
|
<P> test123
|
|
|
|
|
|
|
|
<P> test
|
|
|
|
|
|
|
|
<P> 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'.
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$awk '/test/ {i=i+1} END {print i}' /tmp/dummy
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
<P> 3
|
|
|
|
|
|
|
|
<P> 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'.
|
2000-06-12 18:09:51 +00:00
|
|
|
|
2000-07-05 17:23:44 +00:00
|
|
|
<bf/grep/ (print lines matching a search pattern)
|
2000-06-12 18:09:51 +00:00
|
|
|
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> 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.
|
|
|
|
<tscreen><verb>
|
|
|
|
$grep "look for this" /var/log/messages -c
|
|
|
|
</verb></tscreen>
|
|
|
|
<P> 12
|
|
|
|
<P> The string "look for this" has been found 12 times in the file /var/log/messages.
|
|
|
|
|
|
|
|
<P> [ok, this example was a fake, the /var/log/messages was tweaked :-)]
|
|
|
|
|
|
|
|
<bf/wc/ (counts lines, words and bytes)
|
|
|
|
|
|
|
|
<P> 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:
|
|
|
|
<it/"bash introduction/
|
|
|
|
<it/ howto test file"/
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$wc --words --lines --bytes /tmp/dummy
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
<P> 2 5 34 /tmp/dummy
|
|
|
|
|
|
|
|
<P> Wc doesn't care about the parameter order. Wc always prints them in a standard order, which is,
|
2016-01-17 20:46:43 +00:00
|
|
|
as you can see: <lines><words><bytes><filename>.
|
2000-07-05 17:23:44 +00:00
|
|
|
|
|
|
|
<bf/sort/ (sort lines of text files)
|
|
|
|
|
|
|
|
<P> This time the dummy file contains the following text:
|
|
|
|
<P> <it/"b/
|
|
|
|
<P> <it/c/
|
|
|
|
<P> <it/a"/
|
|
|
|
<tscreen><verb>
|
|
|
|
$sort /tmp/dummy
|
|
|
|
</verb></tscreen>
|
2000-06-12 18:09:51 +00:00
|
|
|
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> This is what the output looks like:
|
|
|
|
|
|
|
|
<P> <it/a/
|
|
|
|
<P> <it/b/
|
|
|
|
<P> <it/c/
|
|
|
|
|
|
|
|
<P> Commands shouldn't be that easy :-)
|
|
|
|
<bf/bc/ (a calculator programming language)
|
|
|
|
|
|
|
|
<P> 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
|
|
|
|
<P> I start bc using the -q parameter to avoid a welcome message.
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
$bc -q
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
<P> <it/1 == 5/
|
|
|
|
<P> <it/0/
|
|
|
|
<P> <it/0.05 == 0.05/
|
|
|
|
<P> <it/1/
|
|
|
|
<P> <it/5 != 5/
|
|
|
|
<P> <it/0/
|
|
|
|
<P> <it/2 ^ 8/
|
|
|
|
<P> <it/256/
|
|
|
|
<P> <it/sqrt(9)/
|
|
|
|
<P> <it/3/
|
|
|
|
<P> <it/while (i != 9) {/
|
|
|
|
<P> <it/i = i + 1;/
|
|
|
|
<P> <it/print i/
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> <it/}/
|
2000-07-05 17:23:44 +00:00
|
|
|
<P> <it/123456789/
|
|
|
|
<P> <it/quit/
|
|
|
|
|
|
|
|
<bf/tput/ (initialize a terminal or query terminfo database)
|
|
|
|
|
|
|
|
<P> A little demonstration of tput's capabilities:
|
|
|
|
<tscreen><verb>
|
|
|
|
$tput cup 10 4
|
|
|
|
</verb></tscreen>
|
|
|
|
<P> The prompt appears at (y10,x4).
|
|
|
|
<tscreen><verb>
|
|
|
|
$tput reset
|
|
|
|
</verb></tscreen>
|
|
|
|
<P> Clears screen and prompt appears at (y1,x1). Note that (y0,x0) is the upper left corner.
|
|
|
|
<tscreen><verb>
|
|
|
|
$tput cols
|
|
|
|
</verb></tscreen>
|
|
|
|
<it/80/
|
|
|
|
<P> Shows the number of characters possible in x direction.
|
2016-04-01 14:50:03 +00:00
|
|
|
<P> It is higly recommended to be familiarized with these programs (at least). There are tons of
|
2000-07-05 17:23:44 +00:00
|
|
|
little programs that will let you do real magic on the command line.
|
|
|
|
<P> [some samples are taken from man pages or FAQs]
|
|
|
|
</sect1>
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- More Scripts -->
|
|
|
|
<sect>
|
|
|
|
More Scripts
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Applying a command to all files in a directory.
|
|
|
|
<P>
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
Sample: A very simple backup script (little bit better)
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
#!/bin/bash
|
2000-06-12 18:09:51 +00:00
|
|
|
SRCD="/home/"
|
|
|
|
TGTD="/var/backups/"
|
|
|
|
OF=home-$(date +%Y%m%d).tgz
|
2022-01-21 07:41:46 +00:00
|
|
|
tar -czf $TGTD$OF $SRCD
|
2016-02-09 22:09:35 +00:00
|
|
|
</verb></tscreen>
|
2000-06-12 18:09:51 +00:00
|
|
|
<P>
|
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
File re-namer
|
|
|
|
<P>
|
|
|
|
<tscreen><verb>
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
#!/bin/sh
|
|
|
|
# renna: rename multiple files according to several rules
|
|
|
|
# written by felix hudson Jan - 2000
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
#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
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# check for the prefix condition
|
|
|
|
if [ $1 = p ]; then
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
#we now get rid of the mode ($1) variable and prefix ($2)
|
|
|
|
prefix=$2 ; shift ; shift
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# 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!!
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
if [$1 = ]; then
|
|
|
|
echo "no files given"
|
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# 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
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
#we now exit the program
|
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# 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
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
if [$1 = ]; then
|
|
|
|
echo "no files given"
|
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
for file in $*
|
|
|
|
do
|
|
|
|
mv ${file} $file$suffix
|
|
|
|
done
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# check for the replacement rename
|
|
|
|
if [ $1 = r ]; then
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
shift
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# i included this bit as to not damage any files if the user does not specify
|
|
|
|
# anything to be done
|
|
|
|
# just a safety measure
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
if [ $# -lt 3 ] ; then
|
|
|
|
echo "usage: renna r [expression] [replacement] files... "
|
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# remove other information
|
|
|
|
OLD=$1 ; NEW=$2 ; shift ; shift
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# 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'
|
2016-04-01 15:13:22 +00:00
|
|
|
# this is a simple command line program that parses standard input and
|
2000-06-12 18:09:51 +00:00
|
|
|
# replaces a set expression with a give string
|
|
|
|
# here we pass it the file name ( as standard input) and replace the nessesary
|
|
|
|
# text
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
for file in $*
|
|
|
|
do
|
|
|
|
new=`echo ${file} | sed s/${OLD}/${NEW}/g`
|
|
|
|
mv ${file} $new
|
|
|
|
done
|
|
|
|
exit 0
|
|
|
|
fi
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# 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
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
# done!
|
2016-02-09 22:09:35 +00:00
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
|
|
|
<sect1>
|
|
|
|
File renamer (simple)
|
|
|
|
<p>
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash
|
|
|
|
# renames.sh
|
|
|
|
# basic file renamer
|
|
|
|
|
|
|
|
criteria=$1
|
|
|
|
re_match=$2
|
|
|
|
replace=$3
|
2016-02-09 22:09:35 +00:00
|
|
|
|
|
|
|
for i in $( ls *$criteria* );
|
2000-06-12 18:09:51 +00:00
|
|
|
do
|
|
|
|
src=$i
|
|
|
|
tgt=$(echo $i | sed -e "s/$re_match/$replace/")
|
|
|
|
mv $src $tgt
|
|
|
|
done
|
|
|
|
</verb></tscreen>
|
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
<sect>
|
|
|
|
When something goes wrong (debugging)
|
|
|
|
<sect1>
|
2016-02-09 22:09:35 +00:00
|
|
|
Ways Calling BASH
|
2000-06-12 18:09:51 +00:00
|
|
|
<p> A nice thing to do is to add on the first line
|
|
|
|
<tscreen><verb>
|
|
|
|
#!/bin/bash -x
|
|
|
|
</verb></tscreen>
|
|
|
|
<P> This will produce some intresting output information
|
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
<sect>
|
|
|
|
About the document
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> Feel free to make suggestions/corrections, or whatever you think
|
2000-06-12 18:09:51 +00:00
|
|
|
it would be interesting to see in this document. I'll try to update
|
|
|
|
it as soon as I can.
|
|
|
|
<sect1>
|
|
|
|
(no) warranty
|
|
|
|
<P> This documents comes with no warranty of any kind.
|
2016-02-09 22:09:35 +00:00
|
|
|
and all that
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
<sect1>
|
2000-07-18 14:15:50 +00:00
|
|
|
Translations
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Italian: by William Ghelfi (wizzy at tiscalinet.it)
|
2000-07-27 13:51:54 +00:00
|
|
|
<htmlurl name="is here" url="http://web.tiscalinet.it/penguin_rules">
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> French: by Laurent Martelli
|
2000-07-27 13:51:54 +00:00
|
|
|
<htmlurl name="is missed" url="http://">
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Korean: Minseok Park
|
2000-07-27 13:51:54 +00:00
|
|
|
<htmlurl url="http://kldp.org" name="http://kldp.org">
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Korean: Chun Hye Jin
|
2000-07-27 13:51:54 +00:00
|
|
|
<htmlurl url="" name="unknown">
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> Spanish: unknow
|
2000-07-27 13:51:54 +00:00
|
|
|
<htmlurl url="http://www.insflug.org" name="http://www.insflug.org">
|
2016-02-09 22:09:35 +00:00
|
|
|
<p> I guess there are more translations, but I don't have any info of them,
|
2000-07-27 13:51:54 +00:00
|
|
|
if you have it, please, mail it to me so I update this section.
|
2000-07-18 14:15:50 +00:00
|
|
|
</sect1>
|
|
|
|
<sect1>
|
2000-06-12 18:09:51 +00:00
|
|
|
Thanks to
|
|
|
|
<P>
|
|
|
|
<itemize>
|
2000-07-18 14:15:50 +00:00
|
|
|
<item> People who translated this document to other languages (previous section).
|
2000-06-22 18:54:39 +00:00
|
|
|
<item> Nathan Hurst for sending a lot of corrections.
|
|
|
|
<item> Jon Abbott for sending comments about evaluating arithmetic expressions.
|
|
|
|
<item> Felix Hudson for writing the <it/renna/ script
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> Kees van den Broek
|
2019-04-01 16:24:13 +00:00
|
|
|
(for sending many corrections, re-writting useful commands section)
|
2000-06-22 18:54:39 +00:00
|
|
|
<item> Mike (pink) made some suggestions about locating bash and testing files
|
2016-02-09 22:09:35 +00:00
|
|
|
<item> Fiesh make a nice suggestion for the loops section.
|
2000-07-05 17:23:44 +00:00
|
|
|
<item> Lion suggested to mention a common error (./hello.sh: Command not found.)
|
2019-04-01 16:25:21 +00:00
|
|
|
<item> Andreas Beck made several corrections and comments.
|
2000-06-12 18:09:51 +00:00
|
|
|
</itemize>
|
|
|
|
</sect1>
|
2000-06-20 14:41:52 +00:00
|
|
|
<sect1>
|
|
|
|
History
|
2019-04-01 16:25:21 +00:00
|
|
|
<p> New translations included and minor corrections.
|
2019-04-01 16:24:13 +00:00
|
|
|
<p> Added the section useful commands re-writen by Kess.
|
2000-07-05 17:23:44 +00:00
|
|
|
<p> More corrections and suggestions incorporated.
|
2000-06-22 18:54:39 +00:00
|
|
|
<p> Samples added on string comparison.
|
2019-04-01 16:25:21 +00:00
|
|
|
<p> v0.8 droped the versioning, I guess the date is enough.
|
2000-06-22 18:54:39 +00:00
|
|
|
<p> v0.7 More corrections and some old TO-DO sections written.
|
|
|
|
<p> v0.6 Minor corrections.
|
|
|
|
<p> v0.5 Added the redirection section.
|
2019-04-01 16:25:21 +00:00
|
|
|
<p> v0.4 disappeared from its location due to my ex-boss and this doc found its new place
|
2000-06-22 18:54:39 +00:00
|
|
|
at the proper url: www.linuxdoc.org.
|
2000-06-20 14:41:52 +00:00
|
|
|
<p> prior: I don't rememeber and I didn't use rcs nor cvs :(
|
|
|
|
</sect1>
|
|
|
|
|
2000-06-12 18:09:51 +00:00
|
|
|
<sect1>
|
|
|
|
More resources
|
|
|
|
<P>
|
|
|
|
<P> Introduction to bash (under BE)
|
2000-06-20 14:41:52 +00:00
|
|
|
<htmlurl url="http://org.laol.net/lamug/beforever/bashtut.htm"
|
|
|
|
name="http://org.laol.net/lamug/beforever/bashtut.htm">
|
2016-04-08 22:14:15 +00:00
|
|
|
<htmlurl url="https://web.archive.org/web/20031203073810/http://org.laol.net/lamug/beforever/bashtut.htm"
|
|
|
|
name="Link defunct, but here's a link from the Wayback Machine">
|
2016-02-09 22:09:35 +00:00
|
|
|
<P> Bourne Shell Programming
|
|
|
|
http://207.213.123.70/book/
|
2000-06-12 18:09:51 +00:00
|
|
|
</sect1>
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
</article>
|