| 0 comments ]

A brief scripting introduction

What is the purpose of writing a script?

Both the Windows and Linux clients have console or terminal sessions allowing users to issue basic commands. These commands are generally providing simple information such as the systems 'host name' or IP address but can also be used to manage the system in a very effective manor. Scripts allow for users to enhance functionally by writing a set of tasks in a single file which then can be executed together by the script to handle a set of tasks.

In Windows, the terminal session is referred to as "DOS prompt" in reference to when DOS ran as the primary OS before Windows 95 was released. Now, like how it has always been with Unixes (Linux), the Windows terminal is integrated into the core Operating System. In Linux it can be referred to as a Terminal prompt, Terminal session, or a "bash" shell.

The command line is very powerful tool, especially in Linux where you can do all kinds of things from updating the system packages quickly, backing up files, connecting to other machines, starting or reseting your networking settings, shutting down the system, locating files (with locate), installing packages (i.e. RPM command) and so forth. Many times it requires more than one command to accomplish a goal and that is where "shell scripts" come in to play.

For more detailed information about programming with bash, use the free http://tldp.org/ external website:

The Linux "Bash" shell

A "shell" is a program which interprets commands, either typed in directly by the user, or contained in a file called a "shell script", which is a simple interpreted program. In Linux it is located in the system 's /bin directory (i.e. /bin/bash ).

Linux has a variety of different shells, but certainly the most popular is "bash", and will be only the only one described here. Also, a commonly used shell is the "korn" shell as it is the default shell for the AIX Unix Operating System. Some of the others have remained largely because there are many people who have become accustomed to them and don't wish to change, or because they are aimed at a specialized set of users.

What is with all of these acronyms?
Unix (Linux) uses a lot of acronyms which reduces coding from less typing but can seem confusing or even somewhat humorous (e.g. yacc="yet another compiler compiler"). Most shells end in "sh", and include ksh (korn shell), csh (C shell... seashell, get it?) and bash (Bourne again shell).

Accessing the terminal

The easiest way to access the terminal, once you have logged in as the new user you created, is to right-click on the Desktop and select "Open Terminal". Otherwise, you can locate the terminal icon from the computer menu system at the bottom of the screen.

Another way of accessing the terminal is to load Linux in text mode. Many servers are configured not to load graphics by default, so the first thing you'd meet is a login prompt in text mode. "Home" or "desktop" computers on the other hand usually start up in graphics mode.

You can try the text-mode prompt easily by pressing Alt-Ctrl-F1 to switch to text mode and Alt-Ctrl-F7 to switch back. Actually, from Alt-Ctrl-F1 to Alt-Ctrl-F6 are usually set up as 6 individual text-mode login prompts, while Alt-Ctrl-F7 is the graphics mode.

Issuing terminal commands

To issue a command type in the words and symbols as given and press Enter (or Return) at the end. Keep in mind that, as with almost everything else in Linux, the commands are case-sensitive. So, if you're supposed to type in "ls", typing "LS" won't work.

For example:

  • the echo command prints text to the screen:
    $ echo "hello world"
    hello world
  • the date command can be used to print out the date to the screen:
    $ date
    Wed Nov 28 12:50:28 EST 2007


A Beginner's script


Let's now create our first script:

  1. Open a terminal session
  2. open a text editor
    (For example, you can use a graphical tool to edit a script if you do not know the command line text editors such as 'vi'.)
    gedit myfile.sh &
  3. Input the following text:
    #!/bin/bash
    # -- This is my first script.

    echo "Hello World!"
    date
  4. Save the file and return to the command prompt
  5. Now make the script "executable" by allowing users to run it:
    chmod a+x ./myfile.sh

    ( the './' refers to the current directory, if the file is in another directory use the full path like /home/userid/myfile.sh )

  6. Now run the application:
    ./myfile.sh

    (should print out hello world and the date)

Looking at this script:

This script has only a few lines. The first indicates the system which program to use to run the file. The second line is a comment because it starts with a '#'. The third and fourth lines are the actions performed by this script, which prints 'Hello World' and the date on the terminal. Not all the impressive or functional but illustrates potential.

If you receive and error like *./myfile.sh: Command not found. Probably the first line '#!/bin/bash' is wrong, issue the command 'which bash' to see where bash is located and confirm you are running the script properly (i.e. try using the full path to run it).

Simple Example Scripts

  • Backup my home folder to one tarfile:
    (which is saved in tmp and can be copied or burned to CD)
    #!/bin/bash
    tar -cZf /tmp/my-backup.tgz /home/user_name
  • Backup my home folder to another Linux system:
    (must have user account and SSH running on the other machine)
    #!/bin/bash
    rsync -avz -e ssh /home/user_name/ remoteuser@remotehost:/remote/dir
  • Restore my home folder *from* another Linux system:
    (must have user account and SSH running on the other machine)
    #!/bin/bash
    rsync -avz -e ssh remoteuser@remotehost:/remote/dir /home/user_name/
  • Restart the network services on a RHEL based system:
    #!/bin/bash
    echo "Restarting networking services ..." ;sleep 3
    /sbin/service network restart
  • Play several games of craps and print the results:
    Playing Craps with Bash

Example Script with Functions


Functions

This example introduces a few things, the main thingis the use of functions. Functions are great because coders can take a chunk of code (which is really a task) and call it with a single command when needed. This makes debugging much easier, cleans up the code, and makes the code portable as functions can be copied and pasted into new scripts. This is generally called procedural programming.

In the example below, a function called gather_user_input was created and it reads the input from the user. The function uses the following notation:

function() {
..... some code .....
}

There are three functions being used in the example below: *gather_user_input, calculate_costs,
print_user_data* . These functions will do NOTHING until they are called somewhere in the script. For example, if a script contains scripts but never calls them, the script will simply do nothing when run. In our example, the scripts are all called in one area near the bottom of the script. Traditionally scripts flow in such a way because functions should be defined before they are called upon.

Script details:

  • In this example it's simple, first we call the gather_user_input function which sets a bunch of variables. For instance the variable user_mpg stores the numeric value the user types in for their vehicle's mpg. We could have done this any way we liked but choose to ask for user input all in one function.
  • Next we call the calculate_costs function which uses the bc calculator to add up values. Looks complicated but it isn't, the command
    gallons_weekly=$(echo "scale=2;${miles_week}/${user_mpg}" |bc)

    can be found on the Internet or the Advanced bash programming guide (also online), where the user's miles driven per week is divided by their mpg to figure out gallons.

  • Lastly, we've decided to put all of the output printing in one function called print_user_data since we really want all of the results or none at all. This helps with debugging in the long run.

In short, this script really is doing three major things, calling three functions which each of them accomplish some task. The variables are "global" so once they are set they can be used in each function, that keeps things simple. However, users can "pass" variables around which is much more advanced and usually unnecessary.

The ./calc_miles4.sh script

#!/bin/bash
# Calculate MPG and stuff for autos
# Version 4

#### FUNCTIONS GET PASSED OVER UNTIL CALLED

# function - gather user info
gather_user_input(){
echo "How many miles do you drive per day (remember to include sat/sun)?"
read miles_week
miles_week=$(echo "scale=2;${miles_week}*7" |bc)
echo "What is your Miles Per Gallon (mpg)?"
read user_mpg
echo "What is the price per gallon?"
read price_gal

# calculate automatic information from above
miles_monthly=$(echo "scale=2;${miles_week}*4" |bc)
miles_yearly=$(echo "scale=2;${miles_monthly}*12" |bc)

}

#generate user costs
calculate_costs(){
local price_per_gal=$1
#gals used per week
gallons_weekly=$(echo "scale=2;${miles_week}/${user_mpg}" |bc)

#gallons used daily
gallons_daily=$(echo "scale=2;${gallons_weekly}/7" |bc)

#daily cost
daily_cost=$(echo "scale=2;${gallons_daily}*${price_per_gal}" |bc)

#weekly cost
weekly_cost=$(echo "scale=2;${daily_cost}*7" |bc)

#monthly cost
monthly_cost=$(echo "scale=2;${weekly_cost}*4" |bc)

#yearly cost
yearly_cost=$(echo "scale=2;${monthly_cost}*12" |bc)

#cost per mile
per_mile_cost=$(echo "scale=2;${yearly_cost}/${miles_yearly}" |bc)
}

# function - print out calculations and data
print_user_data(){
echo "Usability Results::"
echo " Miles driven: $miles_week mi per week"
echo " MPG: $user_mpg mpg"
echo " Miles put on car: $miles_yearly mi per year ( $miles_monthly per month )"
echo " Gallons used daily: g $gallons_daily"
echo " Gallons used weekly: g $gallons_weekly"

echo " "
price_gal=$(echo "scale=2;$price_gal-0.50" |bc) # reduce price per gal by 50 cents
calculate_costs "$price_gal"
echo "Costs Results:"
for (( i=1; i<=3; i++ )) ;do

echo " price @ $price_gal "
echo " Daily: $ $daily_cost ($per_mile_cost per mi) Weekly: $ $weekly_cost Monthly: $ $monthly_cost Yearly: $ $yearly_cost "
echo " "
price_gal=$(echo "scale=2;$price_gal+0.50" |bc)
calculate_costs "$price_gal"

done

}


#### PROGRAM REALLY STARTS HERE
#### THIS IS CALLED THE PROCEDUAL FORMAT (THE BEST REALLY)

gather_user_input
calculate_costs "$price_gal"
print_user_data

Sample output:

[quickm@duvel car_calcs]$  ./calc_miles4.sh
How many miles do you drive per day (remember to include sat/sun)?
60
What is your Miles Per Gallon (mpg)?
24
What is the price per gallon?
2.88
Usability Results::
Miles driven: 420 mi per week
MPG: 24 mpg
Miles put on car: 20160 mi per year ( 1680 per month )
Gallons used daily: g 2.50
Gallons used weekly: g 17.50

Costs Results:
price @ 2.38
Daily: $ 5.95 (.09 per mi) Weekly: $ 41.65 Monthly: $ 166.60 Yearly: $ 1999.20

price @ 2.88
Daily: $ 7.20 (.12 per mi) Weekly: $ 50.40 Monthly: $ 201.60 Yearly: $ 2419.20

price @ 3.38
Daily: $ 8.45 (.14 per mi) Weekly: $ 59.15 Monthly: $ 236.60 Yearly: $ 2839.20

Scripting Tip:

When you use variables in your scripts, you can protect them from shell parsing errors by enclosing the variable or parameter in braces. In some cases, enclosing the name in braces helps to improve readability. While braces are generally not required, they are safer and they remove ambiguity. The bash man page documents some of the cases where the braces are mandatory.

Common Safer
daily_cost=$(echo "scale=2;$gallons_daily*$price_per_gal" |bc)
echo $daily_code
daily_cost=$(echo "scale=2;${gallons_daily}*${price_per_gal}" |bc)
echo ${daily_cost}

0 comments

Post a Comment