Functions

bash's function feature is an expanded version of a similar facility in the System V Bourne shell and a few other shells. A function is sort of a script-within-a-script; you use it to define some shell code by name and store it in the shell's memory, to be invoked and run later.

Functions improve the shell's programmability significantly, for two main reasons. First, when you invoke a function, it is already in the shell's memory; therefore a function runs faster. Modern computers have plenty of memory, so there is no need to worry about the amount of space a typical function takes up. For this reason, most people define as many commonly used functions as possible rather than keep lots of scripts around.

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

The other advantage of functions is that they are ideal for organizing long shell scripts into modular "chunks" of code that are easier to develop and maintain. If you aren't a programmer, ask one what life would be like without functions ( also called procedures or subroutines in other languages) and you'll probably get an earful.

To define a function, you can use either one of two forms:

function functname
               {
               shell commands
               }

or:

               functname 
               ( )
{
    shell commands
               }

There is no functional difference between the two. We will use both forms in this book. You can also delete a function definition with the command unset -f functname.

When you define a function, you tell the shell to store its name and definition (i.e., the shell commands it contains) in memory. If you want to run the function later, just type in its name followed by any arguments, as if it were a shell script.

You can find out what functions are defined in your login session by typing declare -f. The shell will print not just the names but the definitions of all functions, in alphabetical order by function name. Since this may result in long output, you might want to pipe the output through more or redirect it to a file for examination with a text editor. If you just want to see the names of the functions, you can use declare -F.[1] We will look at declare in more detail in Chapter 6.

Apart from the advantages, there are two important differences between functions and scripts. First, functions do not run in separate processes, as scripts do when you invoke them by name; the "semantics" of running a function are more like those of your .bash_profile when you log in or any script when invoked with the source command. Second, if a function has the same name as a script or executable program, the function takes precedence.

This is a good time to show the order of precedence for the various sources of commands when you type a command to the shell:

 

 
  1. Aliases
  2. Keywords such as function and several others, like if and for, which we will see in Chapter 5
  3. Functions
  4. Built-ins like cd and type
  5. Scripts and executable programs, for which the shell searches in the directories listed in the PATH environment variable

Thus, an alias takes precedence over a function or a script with the same name. You can, however, change the order of precedence by using the built-ins command, builtin, and enable. This allows you to define functions, aliases, and script files with the same names, and select which one you want to execute. We'll examine this process in more detail in the section on command-line processing in Chapter 7.

If you need to know the exact source of a command, there are options to the type built-in command that we saw in Chapter 3. type by itself will print how bash would interpret the command, based on the search locations listed above. If you supply more than one argument to type, it will print the information for each command in turn. If you had a shell script, a function, and an alias all called dodo, type would tell you that dodo, as an alias, would be used if you typed dodo.

type has several options that allow you to find specific details of a command. If you want to find out all of the definitions for dodo you can use type -a. This will produce output similar to the following:

$ type -all dodo
dodo is aliased to `echo "Everybody has won, and all must have prizes"'
dodo is a function
dodo ( )
{
    echo "Everybody has won, and all must have prizes"
}
dodo is ./dodo

It is also possible to restrict the search to commands that are executable files or shell scripts by using the -p option. If the command as typed to bash executes a file or shell script, the path name of the file is returned; otherwise, nothing is printed.

The -P option forces type to look for executable files or shell scripts even if the result of -t would not return file.

A further option, -f, suppresses shell function lookup, i.e., only keywords, files and aliases will be returned.[2]

The default output from type is verbose; it will give you the full definition for an alias or function. By using the -t option, you can restrict this to a single word descriptor: alias, keyword, function, builtin, or file. For example:

$ type -t bash
file
$ type -t if
keyword

The -t option can also be used with all other options.

We will refer mainly to scripts throughout the remainder of this book, but unless we note otherwise, you should assume that whatever we say applies equally to functions.

 


[1] The -F option is not available in versions of bash prior to 2.0.

[2] The options -f and -P are not available in versions of bash prior to 2.05b.