ShellScript Nightmares

Objective: SOS with "Hell" scripting

This post is a scratch book to collect some tips about shell script programming that have caused me some silly headaches since I started using Linux and Its usefull shell scripting features


Debuging

When you are in trouble maybe this can help and provide you better debuging info than when running your shell script normally

sh -x shellscript.sh


IFS

IFS is a system var that defines what is considered the field separator in a list when being parsed by a loop. If you don't define it propperly you won't get the desired results.This

for i in `cat /etc/services`; do echo $i; done

is not the same as this

IFS=$'\n';for i in `cat /etc/services`; do echo $i; done

So for god shake be very carefull with the ' marks and the $ ...why this?? i took me enought time to discover this to research why, anyway Ill be graceful if you sent me an email in case you know


String assignment

As a good programmer or good-wannabe programmer you may want your code to be clean an readable, thus you may assign values something like this foo = 7. NOPE NOPE NOPE, your shell is not going to like it, it expects foo=7, this is no spaces in between


Conditionals

If clauses can be used like this:

if [ expression ]
then
    <actions_if_true>
else
    <actions_if_false>
fi
#or
[[ <expression> ]] && <actions_if_true> || <actions_if_false>
#or using the "test" clause

It is very important to respect the blank spaces between the brackets

In order to use double conditions, it should be

# expression1 and expression2 must be true
if [ expression1 -a expression2 ]
if [ expression1 ] && [ expression2 ]
# either expression1 or expression2 have to be true
if [ expression1 -o expression2 ]
if [ expression1 ] || [ expression2 ]


String comparison

After reading the last tip you would use string comparison inside conditional clauses like this:

if [ $foo="something" ]
...

NOOOOOOOOOOOOPE!! Shell scripting does not like it this way, you should separate it or It will understand you are just assigning. This should be correct:

if [ $foo = "something" ]
...

By the way take care with strings that contain blank spaces, in that case your comparison should look like:

if [ "$foo" = "something containing blank spaces" ]
...


Command output assignment

In the same way you assing a value to a variable you can assign the output of a function or external command, to do so you would use the following syntax:

foo=`cat /etc/services`

Bear in mind there shouldn't be any blank space surrounding the = sign


Number comparison

When you are comparing numbers in a conditional clause you must do it in the following way, this is, using -eq, -lt, -gt, etc.

if [ 1 -eq $i ]

Bear in mind there shouldn't be any blank space surrounding the = sign


Function return value

Shell script does not have "return" clause, therefore the first value you "echoed" inside a function is taken as the return value. Wait I din't explain how to define a funcion:

function_A(){
sum=`expr $1 + $2`
echo "Im the return value:$sum"
}

param1=1
param2=2
echo `function_A $param1 $param2`

Keep an eye on the following things


Debuggin help

When you have nested loops you want to stop things to see how the script is running, you can achieve this by using a "readline" stop that will be continued after you press the enter key:

...
read $foo
...


Floating point calculation

Believe it or not but you cannot use decimal numbers inside shell script, therefore you carry those decimal/floating point numbers contained in string variables and then you operate them with a command called bc. An example can be seen below:

function_A(){
sum=`echo "$1+$2"|bc`
echo "Im the return value:$sum"
}

param1=1.2
param2=2.8
echo `function_A $param1 $param2`


Strictly integer variables

Variables in Shellscript tend to be types-bisexual they can accept strings or numbers. In some conditional clauses we see that the shellscript parser is complaining about the types that should be equal. For this cases you can define an strictly int variable and assign it a number from a string variable that will be casted to integer.

max_hits=10
typeset -i hit=0
hit="4"
if [ $max_hits -lt $hit ]
...

Otherwise in the if clause we would see an "unary operation expected" exception.


Bash arrays

wow yeah! Bash shell do handle arrays, its usage is describe in the following examples

#instantiation example
array=(11 2 3 4 5 10 8)
#or
array[0]=0
#length
${#ports[*]}
#read form it, $i is a number
${ports[$i]}
#write to it, $i is a number
ports[$i]=7


Concurrent execution

Commands in a shellscript are executed in sequential order, this is command in line 4 won't be executed before command in line 3 is finished. If we wanted the script not to wait for certain commands or group or commands we use the & symbol.

echo "sequential execution 1"
sleep 2
echo "sequential execution 2"
{
sleep 2
echo "sequential execution 3"
} &
echo "sequential execution 4"
sleep 2

The sequential execution 4 will appear before the execution 3 because the concurrent lines do not make the script wait for them

ShellScriptNightmaresPost (last edited 2009-10-31 20:36:06 by eslimasec)

Locations of visitors to this page