Practical Introduction to BASH

BASH, aka Bourne Again SHell, is probably the most wide-spread shell for *nix like systems (no discussions about this, please; if you prefer some other, just enjoy, I’m not making anyone use bash).

There are many intros out there, but most of them are more about syntax etc., with just a little practical use.
I wrote quite a few bash scripts, but it’s not my primary “language” of choice; so I often need a fast reminder, rather than textbook. That’s why I compiled this simple “list” or “intro” to use as a reference. Maybe someone else will find this useful also.

This intro presumes you do have some programming background (at least basics of any C-like language – C/C++, Java, C#, Pascal, … all will do), and that you know what you want to do.
So if you don’t need much of a textbook stuff, and need a fast “how to use”, or “what to use” reference, you’re at the right place.

This tutorial lacks stuff about interactive processing (asking user for input, etc.); I might create another post about it, if it is a wanted topic…

For a great reference for more advanced topics, check out Advanced Bash-Scripting Guide by Mendel Cooper.

Happy coding! 🙂

Table of contents

Basics
Outputs, redirects and pipes
Variables, parameters and return codes
Conditionals, loops etc.
if - then - [else]
case (commonly known as switch - case)
for, while, until
String and arithmetic operators
Few warnings

Basics

All script files for bash should start with

#!/bin/bash

or whereever your bash is located.

Throughout this reference, I end all bash commands with semicolon. This is not really required, but it’s a good practice. Whenever you need to put several commands on one line, you can separate them using semicolon.

Comments are denoted by #, and comments are single lined (all from and including # till the end of line is comment).

Outputs, redirects and pipes

echo "Some text";

prints “Some text” to console.

ls > /dev/null;

redirects stdout output of ls to null device. Notice that you will still get error messages to console.

ls 2> ~/ls-errors.txt;

redirects stderr output (error messages) of ls to ls-errors.txt file in your home directory, and keeps stdout output in console.

ls &> /dev/null;

redirects all output (both stdout and stderr) of ls to null device. Nothing will be printed to console. This is esp. useful if all you want to do is check for the return code.

You can also redirect stdout to stderr, and vice versa:

ls 2>&1;
ls 1>&2;

– notice there is no space in '2>&1' and '1>&2'!

ls | grep -i '\.txt$';

“pipes” (sends, redirects) output of ls to input of grep (this is a more complicated version of ls *.txt).

Variables, parameters and return codes

Variables are declared and initialized without ‘$’ and used with ‘$’:

mask='*.txt';
ls -l $mask;

Notice that there are no spaces around equals sign in mask='*.txt'! They cannot be there, otherwise bash will think that mask is a command and will try to execute it.

To use output of a command as variable, simply enclose it in $():

filename=~/todays-file-$(date +%Y%m%d);
echo $filename;

Number of parameters to the script can be obtained by $#, and to access individual parameters, use $1, $2, etc..

if [ $# -le '0' ]
then
# No parameters passed to script... what are we gonna do? Exit...
exit;
fi

The same holds for parameters of functions – you can access them using $1, $2, ....

function print_string {
    echo $1;
}
print_string "Hello world!";

Another useful “variable” is return code of last executed command. This is obtained by $?.

ls *.txt &> /dev/null;
if [ $? -eq '0' ]
then
# Now we know there are some *.txt files; do something with them!
    for i in `ls *.txt`
    do
    # Use the .txt file called $i...
    echo $i;
    done
fi

Here we use the fact that ls returns 0 only if some files were found (and listed). See man ls for more info.
Notice that the apostrophes in for i in `ls *.txt` are “backwards” apostrophes (typically they’re on the same key as tilda ‘~’).

To check whether certain parameter is or is not set, you can use -z operator:

if [ -z $1 ]; then echo "Param 1 not set"; fi
if [ ! -z $1 ]; then echo "Param 1 is set"; fi

Conditionals, loops etc.

This is really just a reference (if several versions are presented, it’s for you to choose favourite formatting):

if – then – [else]

if-then:

if [ "foo" = "foo" ]
then
echo "something";
fi

if [ "foo" = "foo" ]; then
echo "something";
fi

if [ "foo" = "foo" ]; then echo "something"; fi

if-then-else:

if [ "foo" = "foo" ]
then
echo "something";
else
echo "thingsome";
fi

if [ "foo" = "foo" ]; then
echo "something";
else
echo "thingsome";
fi

if [ "foo" = "foo" ]; then echo "something"; else echo "thingsome"; fi

case (commonly known as switch – case)

The switch statement, is in bash called simply case:

case "$mystr" in
"case1")
    # do something! mystr is "case1"!
    ;;
"case2")
    # it's ok... mystr is "case2"...
    ;;
*)
    # this is "default", just it's not called so :) ...
    # and as usual, yes, it can be left out if you don't need 'default'
    ;;
esac

for, while, until

Statement for in bash is more like PHP’s foreach than C/C++/Perl/… for. This is due to the nature of what we iterate over – it’s mostly output of some command(s).

for i in $(ls)
do
echo $i;
done

for i in $(ls); do
echo $i;
done

for i in $(ls); do echo $i; done

A more C-like version (using command seq):

for i in `seq 1 10`; do echo $i; done

while is “standard” while:

cnt=1;
while [ $cnt -lt 10 ]
do
echo The counter is $cnt;
let cnt=cnt+1;
done

Notice the use of let!

until is… reversed while, I guess:

cnt=20;
until [ $cnt -lt 10 ]; do
echo The counter is $cnt;
let cnt-=1;
done

String and arithmetic operators

Strings:

"s1" = "s2"     # s1 matches s2
"s1" != "s2"    # s1 does not match s2
"s1" < "s2"     # lexicographical ordering
"s1" > "s2"     # lexicographical ordering
-n s1           # s1 is not zero (non-empty)
-z s1           # s1 is empty

– notice the quotes around s1 and s2 – this is recommended use, since you might get parse errors if either of the string is not defined/empty.

Arithmetic operators:

+
-
*
/
%    # reminder
-lt  # less than
-gt  # greater than
-le  # less or equal
-ge  # greater or equal
-eq  # equal
-ne  # not equal

Few warnings

If you want to use string variables in expressions, and you’re not sure if they’re set, enclose them in double quotes. This is esp. useful for input parameters:

if [ $# -gt '0' ]
then
case "$1" in
"some")
    # something useful
    ;;
"thing")
    # thingsome useful
    ;;
esac
fi

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s