bash

bash scripts

The first line of every bash script should contain #!/bin/bash, preceded by no spaces or tabs. This is more than just a comment -- this line tells the system how to call the interpreter which will execute the script. 

Debugging
To obtain a trace of the execution of a fragment of the code, place the following before that code: 

set -o verbose       or       set -v
set -o xtrace          or       set -x 

and the following after the code:

set +o verbose       or       set +v
set +o xtrace          or       set +x 

Shell variables.
By convention names of shell variables are not capitalized.
VARNAME=VALUE
aa=Hello
bb='Hello world'
aa="$aa my friend"
outputFile=~/csc319/out.txt
user1=abcd1234
nn=345              
unset bb
Remember not to put spaces around the = symbol.

Shell list (array) variables.
There are only lists of strings; there are no lists of lists -- lists are flat.
users=($user1 bcde2345)
echo ${users[0]}
echo ${users[@]}
users=(root ${users[@]} cdef3456) 
${users[0]}=defg4567

Command line parameters
"$0"   -- the name through which the script was invoked
"$1", "$2", ..., "$9", "${10}", ... -- the first, second, ... parameter with which the script was invoked.
"$*" -- the list of all command line parameters as one string, (excluding the name of the script).
"$@" -- the list of all command line parameters as separate string, (excluding the name of the script).
$# -- the number of command line parameters. 

Input
read VAR1 VAR2 ... VARn
stores the first word in VAR1, the second in VAR2, ... and all the remaining words in VARn.
 

Output
echo "cc = $cc"                        -- echo adds a line break after the string.
echo "$bb\n $cc"                      -- Use \n to specify an additional line break.
echo -n "$aa     $bb     $cc"      -- With -n, echo will not add a line break.
echo $aa > $outputFile
echo $cc >> $outputFile
echo "$nn+$nn"                        -- addition not performed.

cat << ENDLABEL                 -- this outputs all the text up to but excluding ENDLABEL.
    ...                                             You can use MESSAGE1_END, etc as the end label.
    ...                                             This feature is called a "here document"
ENDLABEL                          

String operations
There is no concatenation operator. To concatenate strings, put one next to another.
newstring=aaa$string1${string2}bbb
Notice that curly braces can be used to delimit the variable name (so that the shell does not  think the variable  name is string2bbb.)

Boolean expressions
The following tests need to be places between a pair of square brackets [   ]
A space is required after the opening bracket and another space before the closing bracket.

${VARIABLE:+1} -- a test if VARIABLE is defined

= = -- a test if two strings are equal
!= -- a test if two strings are different
< -- a test if two strings are in lexicographic order
> -- a test if two strings are in reverse lexicographic order

-e $file  -- a test if $file exists
-d $file  -- a test if $file exists and is a directory
-f $file  -- a test if $file exists and is a regular file
-r $file -- a test if $file exists and is readable by the current process
-w $file -- a test if $file exists and is writable by the current process
-x $file -- a test if $file exists and is executable by the current process
-s $file -- a test if $file exists and is non-empty.

-gt   -- a test "greater-than" for numeric values
-lt   -- less than
-eq   -- equal
-ne   -- not equal
-ge   -- greater than or equal
-le   -- less than or equal 

Boolean expressions can be combined using -a (conjunction), -o (disjunction) and ! (negation). \( and \) can be used as parentheses for grouping. The entire expression should be palced between a pair of square brackets.

Arithmetic operations
aa=2+2    -- variable aa gets value '2+2'
aa=$((2+2))      -- variable aa gets value 4
$((aa++))              -- now, aa has value 5.
Arbitrary arithmetic expressions with +, -, *, /, ++, -- are allowed.

If-then-else statement

if EXPR1 
then
    ...
    ...
elif EXPR2 
then
    ...
    ...
else
    ...
    ...
fi

There can be any number elif parts.
Elif and else parts are optional.

Switch-case statement

case EXPR in
    STRINGPATTERN1 )
        ...
        ... ;;
    STRINGPATTERN2 )
        ...
        ... ;;
        ...
        ...
esac

Foreach loop

for VARNAME in LIST
do
    ...
    ...
done

For instance:

for user in $users
do
    grep $user /etc/passwd
done

for file in csc*
do
    if [ ! -d $file ]
    then
       chmod o-r $file
    fi
done

While loop

while EXPR
do
    ...
    ...
done

Other features

If you use a file pattern with a wildcard (e.g. csc*), the pattern will expand to the list of files in the present working directory whose names match the pattern.

Output of a command

To store an output of a command in a variable, enclose the command in back-quotes:

fileInfo=`ls -l project.java`

Exit codes
Every unix utility, when it trminates, returns an integer in the range 0-255. This is the integer returned from the main function in C/C++. This integer is stored in the shell variable $? and it is called an exit code. Exit code 0 means that the execution was successful; all other exit codes signify an error. Try:

    ls 
    echo $?
    ls aaaaaaaaaaaaaaaa     (assuming that you have no file of that name)
    echo $?

If you want your script to return an exit code N, use

    exit N

If you want to exit with code 0, it is enough to write

    exit

bash initialization

There are login and non-login shells and interactive and non-interactive shells as explained in the chart below. 

Users can customize their shell behavior by placing appropriate commands in shell initialization files. The commands in these files are executed by new shells, as described in the chart. Executing commands in these files should be contrasted with executing the files themselves -- executing the files would mean that the shell forks and spawns a child shell which executes the commands in file -- these would not initialize the parent shell. Executing commands in a file by the current shell is called sourcing the file. 

  Interactive shell
(one that displays a prompt)
Non-interactive shell
(one that executes commands in a script)
Login shell
(the first shell in a new session)
sources the first of:
~/.bash_profile
~/.bash_login
~/.profile
?
Non-login shell
(any subsequent shell in a session)
sources ~/.bashrc sources $BASH_ENV

After you edit an initialization file, to test the changes, you need either to logout and login again, or force the shell to source the file, for instance:

               $ source ~/.bash_profile
or    $ . ~/.bash_profile

Environment variables are inherited by every child process. In particular, environment variable definitions sourced by the login shell will be known in all the descendant interactive and non-interactive shells, unless one one descendant process removes them.
Warning: When you start a session in the graphic mode (runlevel 5) and then working in a graphic interface (such as KDE) you start a shell window (such as xterm), the shell in this window sometimes does not know the environment variables defined in ~/.bash_profile. This implies that it it is good to put the same environment variable definitions in both in ~/.bash_profile  and in ~/.bashrc. 
Yet better, place environment variable definitions in one of these files and let the other one conditionally source it if these variables are not defined.

Aliases and shell variables sourced by the login shell are not inherited by subsequent shells. Therefore, an appropriate pace for aliases and shell variable definitions is ~/.bashrc.