Saturday, November 27, 2010

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 useful shell scripting features


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


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 properly 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 careful with the ' marks and the $ ...why this?? i took me enough 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


If clauses can be used like this:
if [ expression ]
[[ <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 assign 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 didn't explain how to define a function:
sum=`expr $1 + $2`
echo "Im the return value:$sum"

echo `function_A $param1 $param2`

Keep an eye on the following things
  • The function declaration does not declare parameter types and therefore parentheses are always with no parameters inside
  • The parameters are accesses as $N where "N" is the number of the parameter ($1=param1,$2=param2)
  • In the function invocation the parameters are specified next to the function name without parenthesis.

Debugging 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:
sum=`echo "$1+$2"|bc`
echo "Im the return value:$sum"

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.
typeset -i hit=0
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)
#read form it, $i is a number
#write to it, $i is a number

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.
The sequential execution 4 will appear before the execution 3 because the concurrent lines do not make the script wait for them

No comments:

Post a Comment