Table of Contents for
Linux Shell Scripting Bootcamp

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Linux Shell Scripting Bootcamp by James Kent Lewis Published by Packt Publishing, 2017
  1. Cover
  2. Table of Contents
  3. Linux Shell Scripting Bootcamp
  4. Linux Shell Scripting Bootcamp
  5. Credits
  6. About the Author
  7. Acknowledgement
  8. About the Reviewer
  9. www.PacktPub.com
  10. Customer Feedback
  11. Preface
  12. What you need for this book
  13. Who this book is for
  14. Conventions
  15. Reader feedback
  16. Customer support
  17. 1. Getting Started with Shell Scripting
  18. Demonstrating the use of scripts
  19. Summary
  20. 2. Working with Variables
  21. Validating parameters using conditional statements
  22. Comparison operators for strings
  23. Environment variables
  24. Summary
  25. 3. Using Loops and the sleep Command
  26. Screen manipulation
  27. Indenting your code
  28. Using the for statement
  29. Leaving a loop early
  30. The sleep command
  31. Watching a process
  32. Creating numbered backup files
  33. Summary
  34. 4. Creating and Calling Subroutines
  35. File redirection
  36. Command piping
  37. Subroutines
  38. Using parameters
  39. Making a current backup of your work
  40. Summary
  41. 5. Creating Interactive Scripts
  42. Summary
  43. 6. Automating Tasks with Scripts
  44. Summary
  45. 7. Working with Files
  46. Reading files
  47. Reading and writing files
  48. Reading and writing files interactively
  49. File checksums
  50. File encryption
  51. Summary
  52. 8. Working with wget and curl
  53. wget and recursion
  54. wget options
  55. curl
  56. Summary
  57. 9. Debugging Scripts
  58. Automatic backups
  59. More syntax errors
  60. Logic errors
  61. Using set to debug scripts
  62. Summary
  63. 10. Scripting Best Practices
  64. ssh and scp
  65. Find and use a good text editor
  66. Environment variables and aliases
  67. ssh prompt
  68. Testing an archive
  69. Progress indicator
  70. Creating new commands from a template
  71. Alerting the user
  72. Summary
  73. Index

Using parameters

Okay, let's add some routines to this script to show how to use parameters with a subroutine. In order to make the output look better the cls routine is called first to clear the screen:

Chapter 4 - Script 5

#!/bin/sh
# 6/13/2017
# script5

# Subroutines
cls()
{
 tput clear
 return 0
}

home()
{
 tput cup 0 0
 return 0
}

end()
{
 let x=$COLUMNS-1
 tput cup $LINES $x
 echo -n "X"                 # no newline or else will scroll
}

bold()
{
 tput smso
}

unbold()
{
 tput rmso
}

underline()
{
 tput smul
}

normalline()
{
 tput rmul
}

move()                       # move cursor to row, col
{
 tput cup $1 $2
}

movestr()                    # move cursor to row, col
{
 tput cup $1 $2
 echo $3
}

# Code starts here
cls                          # clear the screen to make the output look better
rc=0                         # return code
if [ $# -ne 1 ] ; then
 echo "Usage: script5 parameter"
 echo "Where parameter can be: "
 echo " home      - put an X at the home position"
 echo " cls       - clear the terminal screen"
 echo " end       - put an X at the last screen position"
 echo " bold      - bold the following output"
 echo " underline - underline the following output"
 echo " move      - move cursor to row,col"
 echo " movestr   - move cursor to row,col and output string"
 exit 255
fi

parm=$1                      # main parameter 1

if [ "$parm" = "home" ] ; then
 home
 echo -n "X"
elif [ "$parm" = "cls" ] ; then
 cls
elif [ "$parm" = "end" ] ; then
 move 0 0
 echo "Calling subroutine end."
end
elif [ "$parm" = "bold" ] ; then
 echo "Calling subroutine bold."
 bold
 echo "After calling subroutine bold."
 unbold
 echo "After calling subroutine unbold."
elif [ "$parm" = "underline" ] ; then
 echo "Calling subroutine underline."
 underline
 echo "After subroutine underline."
 normalline
 echo "After subroutine normalline."
elif [ "$parm" = "move" ] ; then
 move 10 20
 echo "This line started at row 10 col 20"
elif [ "$parm" = "movestr" ] ; then
 movestr 15 40 "This line started at 15 40"
else
 echo "Unknown parameter: $parm"
 rc=1
fi

exit $rc

Since this script only has two extra functions you can just run them. This will be shown one command at a time as follows:

guest1 $ script5
Chapter 4 - Script 5
guest1 $ script5 move
Chapter 4 - Script 5
guest1 $ script5 movestr
Chapter 4 - Script 5

Since we are now placing the cursor at a specific location, the output should make more sense to you. Notice how the command-line prompt reappears where the last cursor position was.

You probably noticed that the parameters to a subroutine work just like with a script. Parameter 1 is $1, parameter 2 is $2, and so on. This is good and bad, good because you don't have to learn anything radically different. But bad in that it is very easy to get the $1, $2, vars mixed up if you are not careful.

A possible solution, and the one I use, is to assign the $1, $2, and so on variables in the main script to a variable with a good meaningful name.

For example, in these example scripts I set parm1 equal to $1 (parm1=$1), and so on.

Take a good look at the script in the next section:

Chapter 4 - Script 6

#!/bin/sh
#
# 6/13/2017
# script6

# Subroutines
sub1()
{
 echo "Entering sub1"
 rc1=0                       # default is no error
 if [ $# -ne 1 ] ; then
  echo "sub1 requires 1 parameter"
  rc1=1                      # set error condition
 else
  echo "1st parm: $1"
 fi

 echo "Leaving sub1"
 return $rc1                 # routine return code
}

sub2()
{
 echo "Entering sub2"
 rc2=0                       # default is no error
 if [ $# -ne 2 ] ; then
  echo "sub2 requires 2 parameters"
  rc2=1                      # set error condition
 else
  echo "1st parm: $1"
  echo "2nd parm: $2"
 fi
 echo "Leaving sub2"
 return $rc2                 # routine return code
}

sub3()
{
 echo "Entering sub3"
 rc3=0                       # default is no error
 if [ $# -ne 3 ] ; then
  echo "sub3 requires 3 parameters"
  rc3=1                      # set error condition
 else
  echo "1st parm: $1"
  echo "2nd parm: $2"
  echo "3rd parm: $3"
 fi
 echo "Leaving sub3"
 return $rc3                 # routine return code
}

cls()                        # clear screen
{
 tput clear
 return $?                   # return code from tput
}

causeanerror()
{
 echo "Entering causeanerror"
 tput firephasers
 return $?                   # return code from tput
}

# Code starts here
cls                          # clear the screen
rc=$?
echo "return code from cls: $rc"
rc=0                         # reset the return code
if [ $# -ne 3 ] ; then
 echo "Usage: script6 parameter1 parameter2 parameter3"
 echo "Where all parameters are simple strings."
 exit 255
fi

parm1=$1                     # main parameter 1
parm2=$2                     # main parameter 2
parm3=$3                     # main parameter 3

# show main parameters
echo "parm1: $parm1  parm2: $parm2  parm3: $parm3"

sub1 "sub1-parm1"
echo "return code from sub1: $?"

sub2 "sub2-parm1"
echo "return code from sub2: $?"

sub3 $parm1 $parm2 $parm3
echo "return code from sub3: $?"

causeanerror
echo "return code from causeanerror: $?"

exit $rc

And here's the output

Chapter 4 - Script 6

There are some new concepts here and so we will go through this one very carefully.

First, we define the subroutines. Notice that a return code has been added. A cls routine has also been included so that a return code could be shown.

We are now at the start of the code. The cls routine is called and then the return value from it is stored in the rc variable. Then the echo statement showing which script this is will be displayed.

So, why did I have to put the return code from the cls command into the rc var? Couldn't I have just displayed it after the echo of the script title? No, because the echo $? always refers to the command immediately preceding it. This is easy to forget so make sure you understand this point.

Okay, so now we reset the rc var to 0 and continue on. I could have used a different variable for this, but since the value of rc is not going to be needed again I chose to just reuse the rc variable.

Now, at the check for parameters, the Usage statement will be displayed if three parameters are not there.

After three parameters are entered we display them. This is always a good idea especially when first writing a script/program. You can always take it out later if it is not needed.

The first subroutine, sub1, is run with 1 parameter. This is checked and an error is displayed if needed.

The same thing happens with sub2, but in this case I intentionally set it to run with only one parameter so that the error message would be displayed.

For sub3, you can see that the main parameters are still accessible from a subroutine. In fact, all of the named variables are, and also the wildcard * and other file expansion tokens. Only the main script parameters cannot be accessed, which is why we put them into variables.

The final routine was created in order to show how errors can be handled. You can see that the tput command itself displayed the error, and then we also captured it in the script.

Finally, the script exits with the main rc variable.

As was mentioned earlier, this script has a lot in it so be sure to study it carefully. Note that when I wanted to show an error in tput, I just assumed that firephasers was going to be an unknown command. I would have been rather surprised if some phasers had actually shot out of (or worse, into) my computer!