Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Part 2 – Commands, Constructions, Script Planning and Layout
Types of Commands in Scripts
When writing scripts it is useful to assign values or strings to name holders which can be reused in the script. Name holders are more commonly referred to as variables, as their contents can be changed.
They are very useful for holding long strings like path names, so you can just type a short name instead of the long path name each time you want to use it. A second use is as a counter which you can add to or subtract from.
Variables are assigned to strings by the syntax
STRINGNAME=”This is a string”
and numbers by
The contents of variables are accessed by the syntax $NUMBER or “$STRINGNAME”. Note the use of double quotes for the string to escape the meaning of embedded spaces or any other special character.
A very neat way of assigning values or contents to variables is by the use of back quotes surrounding shell programs or even another script. This method assigns the results of the enclosed program or script to the variable. For example:
would fill the FOLDERFILES variable with a list of the names of non hidden files or folders in the current folder.
would list all files ending in .jpg. To list the ones ending in jpeg as well:
The square brackets enclose a shell pattern range for the name filter to use.
Question and Answer Commands
This type of command is used to gather information from a user. and involves the use of the echo and read commands. For example,
echo “Enter Name”
The shell will wait for the user to type some input and press the Enter key. It will put the typed entry into the variable NAME.
The echo command is used to print something onto the screen or it can go into a file using a redirection operator. The syntax of echo includes that its argument must be enclosed in quotes.
Echo can append the value of NAME into a file with
[code]echo “$NAME” >> namerecords.txt.[/code
The output of other commands can be used inside scripts to echo the contents of files or list folders to the screen or variables as in the ls examples for folders, or the cat command can put the contents of files onto the screen as in
or to another file as in
cat namerecords.txt > nametemp.txt
A filter is a command that filters its input, changes it in some way, and delivers the changed output.
A useful filter in shell scripts is the tr command, which translates or deletes sets of characters.
A typical use is to change lower case characters to upper case, as the shell is case sensitive, and would see “Tom” as different from “TOM” in a test. The syntax would be
tr a-z A-Z
where a-z is the set of all lower case characters and A-Z the set of all upper case characters.
Construction of Commands.
Lists of Commands
A script can be a simple list of commands. For example you may wish to read several details about NAME like:
echo “Enter First Name”
echo “Enter Last Name
echo “Your Name is: $FIRSTNAME $LASTNAME”
Pipes and Tees
A pipe takes the output from one command and pipes it to another. The symbol for a pipe is “|”. To filter FIRSTNAME to be all upper case, a pipe is used thus:
echo “$FIRSTNAME" | tr a-z A-Z
There can be many pipes in a command line and the output can start before the input has completed.
A tee is used in a pipe to put intermediate output into a file thus:
command | tee interfile.txt | command > outputfile.txt
Conditions and Evaluations
The test program tests the condition of various things. Conditions are evaluated by if, then, else constructions, case patterns and loop constructions, to see if they are true or false.
One can type “test 1 -gt 2” or “[ 1 -gt 2 ]” which both test to see if 1 is greater than 2.
If test condition then else fi Construction
If is usually followed by conditional tests. This is followed by the word then, which is followed by commands for if the condition is true, which can be followed by the word else, followed by more commands for if the condition is false. The final construction termination word is fi. Thus:
if [ “$FIRSTNAME” = “TOM” ]
echo “Hi Tom”
echo “Do I know you?”
Notice the layout. The indentation makes the script more readable and is simply a matter of style, but not necessary for successful script execution, whereas the placement of the if condition then statement else statement fi is important. Some people prefer to type “if [ condition] ; then” where the newline is replaced with the semicolon command concatenation operator. Please yourself about this.
The “if” constructions can be nested as in: “if condition then statements else if another condition then statements else” and so on until each if construct is terminated by its own fi word. This can get quite hard to follow so the next type of command was invented to make things a lot simpler to understand.
Case statement are like nested ifs in operation but are much clearer to follow. The syntax is: “case pattern/value holder in variable pattern) statements break ;; default pattern) statements esac” and will look like this with readability styling.
case names in “$FIRSTNAME”
“TOM”) echo “Hi Tom”
“FRED”) echo “Hello Fred”
*) echo “Do I know You?”
The double semi colons tell case to finish executing the list of commands associated with the found pattern. The default pattern * comes last in the list if you happen to need it. When case has found a matching pattern and executed the commands in its list, no other patterns will be matched.
When you learn a bit more about regular expressions, you can put these in the pattern) part to perform commands on many cases at once. (See BOXOUT Below)
There are while loops, until loops, and for loops. They all have different uses in a shell script.
A while loop means that while a condition is true do the following statements until it is false.
An until loop means until a condition is false do the statements.
A while loop will always do one pass through its construction even if the condition is false whereas an until loop will not.
The for loop can be used in two different constructions. One means that for each pattern/value in variable do the following statements, and the other uses whole number arithmetic to do its evaluation and means that for a start value, evaluate a condition test, do the statements and increment, decrement or otherwise alter the condition value.
For loops work on variables that already have known content whereas the other two are waiting for conditions to be false.
The syntax for the while, until and first for construction are very similar:
while [ “$FIRSTNAME != “TOM” ]
echo “Enter First Name”
This will loop round and round while [FONT="Courier New"]FIRSTNAME[/font is not equal (!=) to TOM and exit past the done word when it is.
The until loop says it the other way.
until [ “$FIRSTNAME” = “TOM” ]
echo “Enter First Name”
And the first for loop.
for Fname in “$FOLDER”
echo “Name is $Fname”
The second for loop construction is often used where you want to perform some statements a certain number of times, but it could be used like the while loop above by giving it count values, making an if test and setting the count value so the test evaluates to false. The (( and )) operators tell the shell it is to perform arithmetic evaluation on the enclosed contents.
for (( COUNT=2; COUNT > 1 ; COUNT++ ))
echo “Enter First Name”
if [ “$FIRSTNAME” = “TOM” ]
As you can see it is a lot simpler to use a while or until loop for this type of information processing, but where you need arithmetic in a loop, this for loop construction is the best option.
You can call another program from a shell script by typing its name into the script. For example you can call the gedit program to edit the file namerecords.txt as:
The script will stop at this point until you exit the gedit program.
You may want the script to exit at this point and run the gedit command. To do this use the & operator at the end of the command. This runs the gedit process in parallel to the current shell. Put an exit statement right after the command which will close and exit the current script.
gedit namerecords.txt &
Finally you can read variable values and other things from another script right into the one that is currently running. This is sometimes called “sourcing” the other file. This is very useful when you learn about functions later on in these articles, as you can fill up scripts with common functions and variables that you can use again and again in other scripts. To call another script like this, use the “source” or “full stop” operator like this:
These files will be read into the current shell script and can be referred to in its commands as if they were actually typed into the current script.
A Practical Example
A simple shell system for acquiring typed in information and displaying a report.
I have visited offices many times where people keep lists on paper or in books for cross reference information, even though they have a Windows computer on their desk. Typing them into a spread sheet and printing them out is often more trouble than it is worth, especially as many Window versions have only the one desktop which is usually covered by the primary application.
Linux, on the other hand, has multiple desktops which can be used and accessed at the click of the mouse. One can be used to enter and view this type of information without having to minimise the primary application. If the user has a modern video card the virtual resolution can be set large enough to have the primary application in one corner and reference lists like these in another.
Another advantage of having these lists on the computer is that others can share them without having to take or see a physical record, the list can be expanded to cater for more than one purpose, and list reports customised for each particular user.
To fail to plan is to plan to fail, so the saying goes, and this is very true for even the smallest job. So we will take the time to plan this simple scripting as a top down task.
Reference lists not easy to update and share on the computer
Aim of script/s:
To write one or more scripts to acquire typed reference information and display it as a report.
Typed information, quit feature
A text record with each field delimited by a # symbol which may be preceded by a whole number index field to make the editing and reporting processes simpler.
Each record in a list of aligned fields
Input acquire loop
Input validation checking
Two base scripts would offer better extensibility, especially if the concept were to be used for other inputs and reports. Optional features for displaying and editing recorded information could help the user.
A check for existing information would also prevent record duplication.
Extra outputs from conclusions:
Display record on input screen by filling one or more fields and pressing Enter
Extra Processing from conclusions:
Check for existing record information
Reporting on selection ranges
End of Plan.
Starting a Script
Now that there is a pretty good plan to follow. For this simple task open your preferred text editor and type in the script header.
Every script starts with a special comment string that tells Linux which shell interpreter to use. This is the string for the bash shell.
Next you should make a comment specifying the whole command line which would be typed at the console to make it run. I am going to follow a convention of adding an identifying extension to each shell script name. I shall call the script for acquiring the information namerecs.sh.
#namerecs.sh [information string]
The square brackets denote an optional argument, which in this case will be used for editing known records.
The next comment describes the operation in English of the script. You can space out comments for readability by putting a single # on intervening lines.
#Script for acquiring reference information, and displaying and editing known records
#in the namerecords.txt file.
Every script you write should have a header like this. Get into the habit now so you can reuse your ideas later on for other projects.
The rest of the script can be laid out logically if you like, or can reflect the way you think. I like the logical way as it helps reuse and to understand what I was trying to do.
This is one form of logical layout, which includes many of the features that you could have in a script. Those marked with a * will be used in this script and except for the script commands are described below.
The header. *
Dot calls to function scripts
Dot calls to variable scripts
Path assignment statements *
Checks for argument and file errors *
Variable assignment statements *
File initialisations *
External command assignments
Internal script functions
Internal Exit conditions *
This script's commands *
Final Returns to a calling script
Final Exit statement *
Path Assignment Statements
These can be very important as changes at this point in the script can allow a working script from your private home folder where it was developed, to be relocated to a global location where all users on a system can access it. Paths are assigned to variable names, which by convention for easy recognition in the script are typed using upper case letters.
Path assignment statements are created in a hierarchy like this.
Variables used globally throughout the program can go here. Some variables, especially those in a loop construct get reassigned just before each time the loop is entered, but the initial values can still be put here, so you can easily see a list of all the variable names used in your script. Often initial values are a null string “”, a space “ “, or zero 0.
Variable assignments are listed in the order in the script they are used.
This makes sure that files or folders used by the script exist, have been emptied, deleted or exist.
If files or folders can't be created, emptied or deleted, the Internal Exit Conditions are used to to exit the program with a meaningful message.
Internal Exit Conditions
Used as above or as functions when errors occur.
Final Exit Statements
This is to make sure that the script will finish and not hang. Usually this is a single exit command, although it can be a whole list of commands to make sure records have been written correctly, special keyboard traps or key assignments have been released, and variables exported to the outer shell have been reassigned.
Summing up so far.
All the basic features of the shell, syntax, script creation tools, types of commands and command constructions have been described in a simple fashion for ordinary users to understand. Script planning and layout of the parts to be used in an example have also been shown.
There are other useful features of the shell and its tools which will be described as you begin to use them in scripts. These extras will make your shell scripts even more powerful and will turn you into a Linux desktop power user.
In the next article you will learn about writing, testing and running practical examples which can be used as a basis for real programs at work.
End of Part 2
BOXOUT 1 A Simple Introduction to Regular Expressions
A regular expression is a pattern that describes a set of strings.
Regular expressions are constructed like arithmetic expressions, by using various operators to combine smaller expressions. The basic building blocks are the regular expressions that match a single character. All letters and digits, are regular expressions that match themselves.
A regular expression may be followed by one of several repetition operators. Common ones are:
`.' The period `.' matches any single character.
`?' The preceding item is optional and will be matched at most once.
`*' The preceding item will be matched zero or more times. This is often called the wild card.
Two regular expressions may be concatenated. This matches any string formed by adding two sub strings that match the added sub expressions.
Two regular expressions may be joined by the operator “|”. The resulting regular expression matches any string matching either sub expression.
A bracket expression contains a list of characters enclosed by [ and ]. It matches any single character in that list; if the first character of the list is the caret ^, then it matches any character *not* in the list. For example,  matches any single digit.
Within brackets, a range consists of two characters separated by a hyphen. It matches any single character that is between the two characters. Thus [a-d] is equivalent to [abcd].
The caret `^' and the dollar sign `$' are special characters that respectively match the empty string at the beginning and end of a line.
This a simple introduction. More information can be found in the manual page for the grep command.
BOXOUT 2 On-line documentation
The shell offers three main types of documentation,
There is command help which is accessed by the syntax “command –help” or in some cases “command -h”. This will print out a short usage help including the syntax of the command and command line options.
There is a manual page which is accessed by the command “man command”. This can be scrolled using the arrow keys, searched for keywords using /word and exited with the q key.
There may be an information page which is accessed by the command “info command”. Sometimes this is the man page. Navigation in info is by special keys which are shown at the top of each page. Using the arrow keys to put the cursor on words preceded by a * and pressing enter will go to that section. The q key exits the info command.
KDE and GNOME help on commands can be accessed from the GUI menu, and often show HTML documentation, although sometimes this is a copy of the info or manual pages.
BOXOUT 3 Simple Shell Functions
Shell functions are a way to group commands for execution using the name of the function.
They are used when one group of commands will be used many times in a script.
Functions are typed using this syntax:
[ function ] function_name () [ arguments ]
list of commands
[ return numeric value ]
} [ redirections]
The word "function" is optional, the () is optional, the optional redirections are performed when the function is executed. A function can return a numeric value, otherwise it returns a zero. The layout is mandatory. Function arguments are accessed as positional parameters, so $1 is the first argument and so on. $# is the number of arguments to the function.
Here is a simple function, its call and the result
#Translate lower to upper case and place the result in the variable UCASE
UCASE=`echo $1 | tr a-z A-Z`
This will echo the word TOMMY. The variable UCASE assigned inside the function is available to the script which called it.