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
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.