Project 75. Use Functions in Scripts"How do I avoid repeating the same piece of code in a shell script?" This project demonstrates the use of Bash functions in shell scripts. It shows you how to use functions as a way of gathering commonly used code into blocks and demonstrates some handy tricks you can employ in your own code. Learn More
Functions' Power, MultipliedIn Project 52, we covered the technique of combining command sequences into functions that can be invoked from the command line. Within Bash scripts, functions work much the same way that functions do in other languages, such as JavaScript and C. When functions are incorporated into a script, they usually are grouped at the top of the file, ahead of the main body of the code. When the script is invoked, Bash reads and parses the functions, which makes them available for use within the actual script. (Functions are not executed when they are parsedonly when they are called by the script.) Tip
Like shell scripts, functions accept arguments, and both use the same syntax to refer to arguments. The first argument passed to a script or function is available in the variable $1; the second, in $2, and the nth, in variable $n. Bash also provides two special variables: $* expands to a list of all arguments, and $# expands to the total number of arguments passed. Because of their shared syntax, arguments passed to a script are not accessible directly by the functions within it, but are available again when a function terminates and the main body of the script executes. One point to be aware of: The variable $0 represents the script name in both the script and its functions. Use the special variable $FUNCNAME to access the name of the current function. Write a FunctionMost nontrivial shell scripts take arguments, and a well-written script will perform some validation on the arguments it receives. Validation methods can vary widely, depending on the nature of the arguments involved (testing for numbers versus text, for example), but most Unix commands and scripts respond the same way when incorrect arguments are passed: by writing a usage line to the terminal. In a script that does a lot of validation, handling this kind of repetitive task is an ideal candidate for a function. Suppose that we are writing a script that does a lot of validation. We might write a simple function to be called from the many points of validation in our hypothetical script. The function would display usage information in the terminal window. Our example function, appropriately called usage, has been taken from a real-world script that creates a new Unix group. usage () { echo "Create a new group" echo " Usage: ${0##*/} groupname gid" if [ "$*" != "" ]; then echo " Error: $*"; fi exit } Tip
In the new-group script, usage displays an informational message and a usage line, and (optionally) an error message preceded by the text Error:. Because this function is called in response to fatal errors, it also shuts down, or exits, the script. A function that simply completes and returns to the main body of the script should not finish on exit: An exit statement terminates the entire script. Let's use our function to report an error when the number of arguments passed to a script is not two. Our script calls the usage function if the wrong number of arguments is passed. if [ $# -ne 2 ]; then usage fi To pass an error message to the function, call it like this. if [ $# -ne 2 ]; then usage "Two arguments expected but $# received" fi Learn More
Unix commands usually write error messages to standard error instead of standard output. We can change our usage function to honor this convention by using a redirection trick. Normally, the echo command writes to standard output, but if we merge standard output into standard error by using the notation 1>&2, or the equivalent >&2, all output will be sent to standard error instead. As an example: echo " Usage: ${0##*/} groupname gid" 1>&2 Learn More
Underline a StringHere's a handy function to underline a line of text. It accepts a line of text as a single argument, displays the text on a line, and places a line of dashes equal in length to the text on the line below it. # Function Underline(string-to-underline) # Display and underline a string. # $1: the string to underline Underline () { local -i len # to hold the length of the string # write out the string and a '-' for each charater len=${#1}; echo "$1" while ((len!=0)); do echo -n "-"; len=len-1; done; echo return 0 } Tip
Our function, named Underline, assigns the number of characters in parameter 1 to the variable len by using the special notation ${#1}. It then displays the text held in parameter 1 and loops to display the appropriate number of dashes below the text. We employ a few more tricks besides ${#1}. Passing option -n to echo stops it from displaying each dash on a new line. Also, we declare len to be a local integer variable in the line local -i len # to hold the length of the string A local variable exists only while its defining function executes and prevents us from accidentally overwriting a variable of the same name from the main script. The option -i makes len an integer variable, allowing us to employ Bash integer expressions such as the condition in Learn More
while ((len!=0)); which loops for as long as the value of the variable len is not equal to 0; and the arithmetic expression len=len-1 which subtracts 1 from the value of len. Learn More
We'd call Underline from the main body of the script in the following manner. Underline "The Title" yielding The Title --------- Tip
|