Bash Scripting Course PDF
Bash Scripting Course PDF
BASH 201
1. Issue a command, or a chain of commands
2. Get results
a. Standard Output
b. Standard Error
c. Exit Code
3. Analyze one or more of the results
4. Act upon the results
1
BASH 301
If you do a sequence of commands more than once, regularly (every couple of weeks) automate
it with a BASH shell script.
Why?
● Eliminates errors
● Saves time
● More fun! Because you are creating which is fundamental to our being
BASH 401
1. Create Functions in BASH shell scripts
2. Create Function Libraries
3. Create Schema Libraries
BASH 101
1. Issue a command: ls
2. Get a result: cimagent cimitra error.txt standard.txt
cimagent.js dirlist.txt output.txt
3. Analyze the result: “I need to remove the .txt files, they aren’t needed”
4. Act upon the result: rm
error.txt standard.txt
output.txt dirlist.txt
2
BASH 201
Standard Output
Issue a command, get some output [ Standard Output ], which by default is directed to the
screen you are in.
3
Issue a command, redirect Standard Output (1>) to a file … instead of the screen
ls 1> ./dirlist.txt
Now let’s see the contents of the file that we redirected Standard Output to
cat dirlist.txt
4
Standard Error
Issue a bogus command, get some output [ Standard Error ], which by default is directed to
the screen you are in.
tiggerslovehoney
Issue a command, redirect Standard Error ( 2> ) to a file … instead of the screen
5
Issue a command, redirect the Standard Output ( 1>) to a file and the Standard Error ( 2>) to
a different file . . . instead of the screen
cat standard.txt
cat error.txt
6
Exit Codes
Every command you call in Linux has an “exit” code
0 = Generally means no error 1 = Generally means error Some other number
generally means error
or warning
You can get the exit code from a command in this manner:
BASH 301
Making Variables
7
MY_TEXT="HELLO WORLD"
declare -i MY_NUMBER="1"
MY_DIR_LISTING=`ls`
echo $MY_TEXT
echo $MY_NUMBER
echo $MY_DIR_LISTING
MY_NUMBER=MY_NUMBER+1
echo $MY_NUMBER
8
Style & Convention
Establish your style . . . . . . stick with it!
webServerRunningState WEB_SERVER_RUNNING_STATE
WebServerRunningState web_server_running_state
You don’t have to use one convention for everything though. For example, functions might use a
certain kind of convention different from variables. And variables that are global might use a
different convention than local variables.
Example Conventions
Example Function Convention Example Variable Conventions
Looks different from variables, explains what Global Variable - Available in the entire script
the function does
WEB_SERVER_RUNNING_STATE
checkWebServerStatus
web_server_running_state
Code Simplicity
Short is good, in the right place. Your goal is to have the least amount of lines of code. However,
you should never scrimp on the names of variables and functions. The names of variables and
functions should always be very descriptive and self-documenting.
9
#!/bin/bash
# Check Web Server Version 1
# Determine if the local web server is running
# curl is a command line web browser
# Use curl to test the default HTTP port (80)
# The web server is local to this Linux box
Save the contents of the script to a Linux box, and make the file executable. On Windows, I use
WinSCP as my editor typically.
To make a script executable in a console session (Generally putty on Windows) type the
following command:
chmod +x /home/scripts/webserver.sh
10
./webserver.sh
or
/home/tkratzer/scripts/webserver.sh
LEARNING NOTE
The construct used in this script is called an if then else fi statement. You can test all kinds of things with this
construct. Another common construct is called an if then fi statement. For example:
if [ $web_server_running_state -ne 0 ]
then
${RESTART_WEB_SERVER}
echo "The web server was restarted"
fi
The if then fi construct is extremely popular since often you only want to take an action only if a condition
exists, and if the condition does not exist you do not want to take any kind of action.
What’s with the fi portion of these constructs? Well, “fi” is the ending of the if statement so it’s kind of like the
opposite of if . . . similar to opening and closing tags < and >. It’s also somewhat humorous in that it isn’t a proper
word, but these weirdisms are common in the Unix/Linux/BASH world which makes for comic relief and endearment
towards the platform and the BASH language.
The -ne is a testing method for numbers. It means not equal to. There are others such as -gt (greater than) -lt (less
than) -eq (equal to).
11
There are a couple of things that I want to improve on in this script. First off the output from the
script is too chaotic. We want to subdue the output from the curl command. It’s really just the
exit code we want to get without all of the other output.
curl check localhost and send the standard output ( 1> ) and standard error ( 2> )
into a black hole ( /dev/null ) because I don’t need the output.
The next thing I want to do is combine the curl command and echo command into one
statement associated with a variable. We use the semicolon command ( ; ) which basically
means, after you do this command, then run another command.
Below is the second version of the BASH script. It has the following improvements:
1. The script is a very quiet script where all the noise from the curl command is filtered out.
This increases the ease of use of the script. Before, we didn’t know if the output was
coming from the script or the curl command.
2. The curl command, and the variable to hold the state of the web server, are now
combined into one element.
#!/bin/bash
# Check Web Server Version 2
# Determine if the local web server is running
# curl is a command line web browser
# Use curl to test the default HTTP port (80)
# The web server is local to this Linux box
12
# Create a variable for restarting the web server
RESTART_WEB_SERVER="rcapache2 restart"
BASH 401
Functions
Function Libraries
Schemas
Functions
The command to restart the web server is currently a global variable called:
$RESTART_WEB_SERVER
However, it is better and more scalable over time to call a function to restart the web server.
This way if we wanted to do more things than restarting the web server we could. Here is how a
function is created:
13
function nameOfFunction()
{
<Commands to run in function>
}
So for example:
function restartWebServer()
{
rcapache2 restart
echo "The web server was restarted"
}
2. Functions must exist above the line in the script that is calling the function
In our web server script, I would like to add another function for logging. Here are the
requirements of the log function:
We will make a second function that will perform the actual trimming of the log. That way this
function can be reused. This will also help to keep the log function smaller and more concise to
the function’s actual purpose.
We will also contain the web server restart and the checking of the web server into their own
two functions called:
14
The checkWebServer() function will be the only function name actually in the body of
the script. There are 3 other functions that are called in this script, but they are called from other
functions. The function names are in blue. The calls to the functions are in yellow.
#!/bin/bash
# Check Web Server Version 3
# Determine if the local web server is running
# curl is a command line web browser
# Use curl to test the default HTTP port (80)
# The web server is local to this Linux box
function trimTextFile()
{
# Assign first passed variable to: text_file_to_trim
text_file_to_trim=$1
15
if [ $current_file_length -lt $max_file_length ]
then
return
fi
temp_file="/tmp/${RANDOM}.tmp"
mv ${temp_file} ${text_file_to_trim}
}
function log()
{
# Assign first passed variable to: input_text_to_log
input_text_to_log=$1
16
# Integer variable for the max number of log lines
declare -i max_log_length="100"
date_string=`date`
function restartWebServer()
{
rcapache2 restart
echo "The web server was restarted"
}
function checkWebServer()
{
# Issue curl command, supress output, get exit code
declare -i web_server_running_state=`curl localhost 2>
/dev/null 1> /dev/null ; echo $?`
if [ $web_server_running_state -ne 0 ]
then
restartWebServer
log "The web server was restarted"
else
echo "The web server is running"
17
fi
}
checkWebServer
Function Libraries
The trimTextFile() function is a pretty handy function. This function could have a lot
more life and usability in other scripts if somehow we could break it away from the
webserver.sh script. We could always copy the function to another script. However, the
problem with that is that if we wanted to improve the function, we would then have to copy the
updated function to other scripts that use that function. Where’s the joy in that!
2. Then read the functions.sh script at the top of the webserver.sh script.
This puts the functions.sh script contents in memory so that the contents of the
functions.sh script can be called from within anywhere within the
webserver.sh script. Here is how you read in an external file:
So for example:
. /home/tkratzer/scripts/function.sh
3. Calls to the trimTextFile()function are simply calls to the function that have
already loaded in memory from the functions.sh script.
Now we have a tidier script file that is short and more concise. Unlike basketball, in the coding
world, shorter is better. Fewer lines of code mean less debugging. See version 4 of our script
18
below. The line that loads the call to the function library is highlighted in green (because
you are now using reusable the code ;))))) ).
#!/bin/bash
# Check Web Server Version 4
# Determine if the local web server is running
# curl is a command line web browser
# Use curl to test the default HTTP port (80)
# The web server is local to this Linux box
. /home/tkratzer/scripts/functions.sh
function log()
{
# Assign first passed variable to: input_text_to_log
input_text_to_log=$1
date_string=`date`
function restartWebServer()
{
19
rcapache2 restart
echo "The web server was restarted"
}
function checkWebServer()
{
# Issue curl command, suppress output, get exit code
declare -i web_server_running_state=`curl localhost 2>
/dev/null 1> /dev/null ; echo $?`
if [ $web_server_running_state -ne 0 ]
then
restartWebServer
log "The web server was restarted"
else
echo "The web server is running"
fi
}
checkWebServer
Schemas
A schema might sound kind of scary, but it’s really a simple idea. Schemas are really just a
static (unchanging) variable library. So instead of a file with a bunch of functions in it like a
function library, a schema is a file with a bunch of pre-established variables. For example:
TEMP_PATH="/tmp"
WEB_SERVER_RESTART_COMMAND="rcapache2 restart"
CIMITRA_RESTART_COMMAND="cimitra restart"
SERVER_INFO=`cat /etc/issue`
20
The name you give to a schema file doesn’t really matter. It can be called something like
schema.lib for example. Or just schema. The actual name is your choice. You read in
your schema file in the exact same manner as a function library. So…
Example:
. /home/tkratzer/scripts/schema.lib
Your function library and your script would generally load the same schema file. This way they
can use common variables. You don’t need to put the #!/bin/bash at the top of the schema
library, but you can if you would like.
MAX_LOG_LENGTH="100"
MAX_AGENT_RETRIES="10"
ADMIN_EMAIL_ADDRESS="tay@cimitra.com"
CIMITRA_APP_SERVER="155.100.111.141"
You read in your variable configuration files in the exact same manner as a function library. So…
Example:
. /home/tkratzer/scripts/variables.cfg
Once the variables are read in they are available by using the following syntax:
${<VARIABLE NAME>}
21
For example:
${MAX_LOG_LENGTH}
The primary purpose behind variable configuration files is so that you don’t have to store
variables that you would want to change in the script that you have created. The script will stay
static, and the configuration file will change as needed. DO NOT use the #!/bin/bash line in a
variable configuration file, because this is not code, it is a configuration file.
Conclusion
Bash is a never-ending journey. You can create very elaborate scripts that total in the thousands
of lines. However, your goal with Bash scripting should always be:
22