3.9. Internal Commands and Builtins

A builtin is a command contained in the bash tool set, literally built in.

getopts

This powerful tool parses command line arguments passed to the script. This is the bash analog of the getopt library function familiar to C programmers. It permits passing and concatenating multiple flags[1] and options to a script (for example scriptname -abc -e /usr/local).

The getopts construct uses two implicit variables. $OPTIND is the argument pointer (OPTion INDex) and $OPTARG (OPTion ARGument) the (optional) argument attached to a flag. A colon following the flag name in the declaration tags that flag as having an option.

A getopts construct usually comes packaged in a while loop, which processes the flags and options one at a time, then decrements the implicit $OPTIND variable to step to the next.

Note

  1. The arguments must be passed from the command line to the script preceded by a minus (-) or a plus (+), else getopts will not process them, and will, in fact, terminate option processing at the first argument encountered lacking these modifiers.

  2. The getopts template differs slightly from the standard while loop, in that it lacks condition brackets.

  3. The getopts construct replaces the obsolete getopt command.

   1 while getopts ":abcde:fg" Option
   2 # Initial declaration.
   3 # a, b, c, d, e, f, and g are the flags expected.
   4 # The : after flag 'e' shows it will have an option passed with it.
   5 do
   6   case $Option in
   7     a ) # Do something with variable 'a'.
   8     b ) # Do something with variable 'b'.
   9     ...
  10     e)  # Do something with 'e', and also with $OPTARG,
  11         # which is the associated argument passed with 'e'.
  12     ...
  13     g ) # Do something with variable 'g'.
  14   esac
  15 done
  16 shift $(($OPTIND - 1))
  17 # Move argument pointer to next.
  18 
  19 # All this is not nearly as complicated as it looks <grin>.
  20 	      


Example 3-39. Using getopts to read the flags/options passed to a script

   1 #!/bin/bash
   2 
   3 # 'getopts' processes command line args to script.
   4 
   5 # Usage: scriptname -options
   6 # Note: dash (-) necessary
   7 
   8 # Try invoking this script with
   9 # 'scriptname -mn'
  10 # 'scriptname -oq qOption'
  11 # (qOption can be some arbitrary string.)
  12 
  13 OPTERROR=33
  14 
  15 if [ -z $1 ]
  16 # Exit and complain if no argument(s) given.
  17 then
  18   echo "Usage: `basename $0` options (-mnopqrs)"
  19   exit $OPTERROR
  20 fi  
  21 
  22 while getopts ":mnopq:rs" Option
  23 do
  24   case $Option in
  25     m     ) echo "Scenario #1: option -m-";;
  26     n | o ) echo "Scenario #2: option -$Option-";;
  27     p     ) echo "Scenario #3: option -p-";;
  28     q     ) echo "Scenario #4: option -q-, with argument \"$OPTARG\"";;
  29     # Note that option 'q' must have an additional argument,
  30     # otherwise nothing happens.
  31     r | s ) echo "Scenario #5: option -$Option-"'';;
  32     *     ) echo "Unimplemented option chosen.";;
  33   esac
  34 done
  35 
  36 shift $(($OPTIND - 1))
  37 # Decrements the argument pointer
  38 # so it points to next argument.
  39 
  40 exit 0

exit

Unconditionally terminates a script. The exit command may optionally take an integer argument, which is returned to the shell as the exit status of the script. It is a good practice to end all but the simplest scripts with an exit 0, indicating a successful run.

set

The set command changes the value of internal script variables. One use for this is to toggle option flags which help determine the behavior of the script (see Section 3.27). Another application for it is to reset the positional parameters that a script sees as the result of a command (set `command`). The script can then parse the fields of the command output.


Example 3-40. Using set with positional parameters

   1 #!/bin/bash
   2 
   3 # script "set-test"
   4 
   5 # Invoke this script with three command line parameters,
   6 # for example, "./set-test one two three".
   7 
   8 echo
   9 echo "Positional parameters before  set \`uname -a\` :"
  10 echo "Command-line argument #1 = $1"
  11 echo "Command-line argument #2 = $2"
  12 echo "Command-line argument #3 = $3"
  13 
  14 echo
  15 
  16 set `uname -a`
  17 # Sets the positional parameters to the output
  18 # of the command `uname -a`
  19 
  20 echo "Positional parameters after  set \`uname -a\` :"
  21 # $1, $2, $3, etc. reinitialized to result of `uname -a`
  22 echo "Field #1 of 'uname -a' = $1"
  23 echo "Field #2 of 'uname -a' = $2"
  24 echo "Field #3 of 'uname -a' = $3"
  25 echo
  26 
  27 exit 0

unset

The unset command deletes an internal script variable. It is a way of negating a previous set. Note that this command does not affect positional parameters.

export

The export command makes available variables to all child processes of the running script or shell. Unfortunately, there is no way to export variables back to the parent process, to the process that called or invoked the script or shell. One important use of export command is in startup files, to initialize and make accessible environmental variables to subsequent user processes (see Section 3.23).

Note

It is possible to initialize and export variables in the same operation, as in export var1=xxx.

readonly

Same as declare -r, sets a variable as read-only, or, in effect, as a constant. Attempts to change the variable fail with an error message. This is the shell analog of the C language const type qualifier.

basename

Strips the path information from a file name, printing only the file name. The construction basename $0 lets the script know its name, that is, the name it was invoked by. This can be used for "usage" messages if, for example a script is called with missing arguments:
   1 echo "Usage: `basename $0` arg1 arg2 ... argn"

dirname

Strips the basename from a file name, printing only the path information.

Note

basename and dirname can operate on any arbitrary string. The filename given as an argument does not need to refer to an existing file.


Example 3-41. basename and dirname

   1 #!/bin/bash
   2 
   3 a=/home/heraclius/daily-journal.txt
   4 
   5 echo "Basename of /home/heraclius/daily-journal.txt = `basename $a`"
   6 echo "Dirname of /home/heraclius/daily-journal.txt = `dirname $a`"
   7 
   8 exit 0

read

"Reads" the value of a variable from stdin, that is, interactively fetches input from the keyboard. The -a option lets read get array variables (see Example 3-90).


Example 3-42. Variable assignment, using read

   1 #!/bin/bash
   2 
   3 echo -n "Enter the value of variable 'var1': "
   4 # -n option to echo suppresses newline
   5 
   6 read var1
   7 # Note no '$' in front of var1, since it is being set.
   8 
   9 echo "var1 = $var1"
  10 
  11 
  12 # Note that a single 'read' statement can set multiple variables.
  13 
  14 echo
  15 
  16 echo -n "Enter the values of variables 'var2' and 'var3' (separated by a space or tab): "
  17 read var2 var3
  18 echo "var2 = $var2      var3 = $var3"
  19 # If you input only one value, the other variable(s) will remain unset (null).
  20 
  21 exit 0

The read command may also "read" its variable value from a file redirected to stdin (see Section 3.13). If the file contains more than one line, only the first line is assigned to the variable. If there is more than one parameter to the read, then each variable gets assigned a successive whitespace delineated string. Caution!

   1 read var1 <data-file
   2 echo "var1 = $var1"
   3 # var1 set to the entire first line of the input file "data-file"
   4 
   5 read var2 var3 <data-file
   6 echo "var2 = $var2   var3 = $var3"
   7 # Note inconsistent behavior of "read" here.
   8 # 1) Rewinds back to the beginning of input file.
   9 # 2) Each variable is now set to a corresponding string, separated by whitespace,
  10 #    rather than to an entire line of text.
  11 # 3) The final variable gets the remainder of the line.
  12 # 4) If there are more variables to be set than whitespace-terminated strings
  13 #    on the first line of the file, then the excess variable remain unset.

true

A command that returns a successful (zero) exit status, but does nothing else.

   1 # Endless loop
   2 while true
   3 # alias for :
   4 do
   5    operation-1
   6    operation-2
   7    ...
   8    operation-n
   9    # Need a way to break out of loop.
  10 done

false

A command that returns an unsuccessful exit status, but does nothing else.

   1 # Null loop
   2 while false
   3 do
   4    # The following code will not execute.
   5    operation-1
   6    operation-2
   7    ...
   8    operation-n
   9    # Nothing happens!
  10 done   

factor

Factor an integer into prime factors.

 bash$ factor 27417
 27417: 3 13 19 37
 	      

hash [cmds]

Record the path name of specified commands (in the shell hash table), so the shell or script will not need to search the $PATH on subsequent calls to those commands. When hash is called with no arguments, it simply lists the commands that have been hashed.

pwd

Print Working Directory. This gives the user's (or script's) current directory (see Example 3-43). The effect is identical to reading the value of the builtin variable $PWD (see Section 3.7).

pushd, popd, dirs

This command set is a mechanism for bookmarking working directories, a means of moving back and forth through directories in an orderly manner. A pushdown stack is used to keep track of directory names. Options allow various manipulations of the directory stack.

pushd dir-name pushes the path dir-name onto the directory stack and simultaneously changes the current working directory to dir-name

popd removes (pops) the top directory path name off the directory stack and simultaneously changes the current working directory to that directory popped from the stack.

dirs lists the contents of the directory stack (counterpart to $DIRSTACK, see below). A successful pushd or popd will automatically invoke dirs.

Scripts that require various changes to the current working directory without hard-coding the directory name changes can make good use of these commands. Note that the implicit $DIRSTACK array variable, accessible from within a script, holds the contents of the directory stack.


Example 3-43. Changing the current working directory

   1 #!/bin/bash
   2 
   3 dir1=/usr/local
   4 dir2=/var/spool
   5 
   6 pushd $dir1
   7 # Will do an automatic 'dirs'
   8 # (list directory stack to stdout).
   9 echo "Now in directory `pwd`."
  10 # Uses back-quoted 'pwd'.
  11 # Now, do some stuff in directory 'dir1'.
  12 pushd $dir2
  13 echo "Now in directory `pwd`."
  14 # Now, do some stuff in directory 'dir2'.
  15 echo "The top entry in the DIRSTACK array is $DIRSTACK."
  16 popd
  17 echo "Now back in directory `pwd`."
  18 # Now, do some more stuff in directory 'dir1'.
  19 popd
  20 echo "Now back in original working directory `pwd`."
  21 
  22 exit 0

source, . (dot command), dirs

This command, when invoked from the command line, executes a script. Within a script, a source file-name loads the file file-name. This is the shell scripting equivalent of a C/C++ #include directive. It is useful in situations when multiple scripts use a common data file or function library.


Example 3-44. "Including" a data file

   1 #!/bin/bash
   2 
   3 # Load a data file.
   4 . data-file
   5 # Same effect as "source data-file"
   6 
   7 # Note that the file "data-file", given below
   8 # must be present in working directory.
   9 
  10 # Now, reference some data from that file.
  11 
  12 echo "variable1 (from data-file) = $variable1"
  13 echo "variable3 (from data-file) = $variable3"
  14 
  15 let "sum = $variable2 + $variable4"
  16 echo "Sum of variable2 + variable4 (from data-file) = $sum"
  17 echo "message1 (from data-file) is \"$message1\""
  18 # Note:                            escaped quotes
  19 
  20 print_message This is the message-print function in the data-file.
  21 
  22 
  23 exit 0

File data-file for Example 3-44, above. Must be present in same directory.

   1 # This is a data file loaded by a script.
   2 # Files of this type may contain variables, functions, etc.
   3 # It may be loaded with a 'source' or '.' command by a shell script.
   4 
   5 # Let's initialize some variables.
   6 
   7 variable1=22
   8 variable2=474
   9 variable3=5
  10 variable4=97
  11 
  12 message1="Hello, how are you?"
  13 message2="Enough for now. Goodbye."
  14 
  15 print_message ()
  16 {
  17 # Echoes any message passed to it.
  18 
  19   if [ -z $1 ]
  20   then
  21     return 1
  22     # Error, if argument missing.
  23   fi
  24 
  25   echo
  26 
  27   until [ -z "$1" ]
  28   do
  29     # Step through arguments passed to function.
  30     echo -n "$1"
  31     # Echo args one at a time, suppressing line feeds.
  32     echo -n " "
  33     # Insert spaces between words.
  34     shift
  35     # Next one.
  36   done  
  37 
  38   echo
  39 
  40   return 0
  41 }  

3.9.1. Job Control Commands

ps

Lists currently executing jobs by owner and process id. This is usually invoked with ax options, and may be piped to grep or sed to search for a specific process (see Example 3-51).

 bash$  ps ax | grep sendmail
 295 ?	   S	  0:00 sendmail: accepting connections on port 25
wait

Stop script execution until all jobs running in background have terminated, or until the job number specified as an option terminates. Sometimes used to prevent a script from exiting before a background job finishes executing (this would create a dreaded orphan process).


Example 3-45. Waiting for a process to finish before proceeding

   1 #!/bin/bash
   2 
   3 if [ -z $1 ]
   4 then
   5   echo "Usage: `basename $0` find-string"
   6   exit 1
   7 fi
   8 
   9 echo "Updating 'locate' database..."
  10 echo "This may take a while."
  11 updatedb /usr &
  12 # Must be run as root.
  13 
  14 wait
  15 # Don't run the rest of the script until 'updatedb' finished.
  16 # You want the the database updated before looking up the file name.
  17 
  18 locate $1
  19 
  20 # Lacking the wait command, in the worse case scenario,
  21 # the script would exit while 'updatedb' was still running,
  22 # leaving it as an orphan process.
  23 
  24 exit 0

suspend

This has the same effect as Control-Z, pausing a foreground job.

stop

This has the same effect as suspend, but for a background job.

disown

Remove job(s) from the shell's table of active jobs.

jobs

Lists the jobs running in the background, giving the job number. Not as useful as ps.

times

Gives statistics on the system time used in executing commands, in the following form:
 0m0.020s 0m0.020s
This capability is of very limited value, since it is uncommon to profile and benchmark shell scripts.

kill

Forcibly terminate a process by sending it an appropriate terminate signal (see Example 3-69).

Note

kill -l lists all the "signals". (See Section 3.26 for more detail on signals).

command

The command directive disables aliases and functions. This leaves only shell builtins, system commands, and commands and scripts accessible via $PATH.

Note

This is one of three shell directives that effect script command processing. The others are builtin and enable, see below.

builtin

This disables both functions and commands in the $PATH, leaving only shell builtins accessible.

enable

This either enables or disables a shell builtin command. As an example, enable -n kill disables the shell builtin kill, so that when Bash subsequently encounters kill, it invokes /bin/kill. The -a option lists all the shell builtins, indicating whether or not they are enabled.

Notes

[1]

A flag is an argument that acts as a signal, switching script behaviors on or off.