back to the table of contents, There exists a May 20, 2019 version at

Shell Operation

  1. Read commands from:
    1. a file,
    2. a string supplied as an argument to the -c invocation option, or
    3. the user's terminal.
  2. Performs alias expansion
  3. Collects tokens seperated by metacharacters, breaking the input into words and operators
  4. Parses the tokens into simple and compound commands.
  5. Performs expansions breaking the expanded tokens into lists of commands, arguments and filenames.
  6. Performs redirections of input/output units (and removes the redirection operators and their operands from the argument list).
  7. Executes the command.
  8. Waits for the command to complete (unless asynchronous execution is reqeusted) and collects its status.
   # causes remaining characters on that line to be ignored

Metacharacters | & ; ( ) < > [space] and [tab] seperate words of a command.

A circumflex (^) indicates a non-printable character, example:
To causes a page eject in a print stream, insert a formFeed
(^L is produced by holding down the CONTROL key then pressing the letter L )
> echo \^L


An apostrophe may not occur between apostrophes, even when preceded by a \, use quotes instead.
   > grep 'don\'t' dafile.txt # will wait for closing apost.

Double Quotes

Enclosing characters in "
Beware of copying/pasting which are a pretty left/right quotes but not for bash!.

ANSI-C Quoting

A word of the form $'string' expands to string, with backslash-escaped characters replaced with
\n newline x0A
\cJ (i.e. ctrl-J )
\\ backslash x5C   aka solidus
\' apostrophe x27   Refered to as "single quote".
\a alert (bell) x07  
\b backspace x08
\r carriage return x0D
\t horizontal tab x09
\f form feed x0C
\v vertical tab x0B
\e ESCape character
x1B used as "lead-in" for terminal specific function (not ANSI C)
\ooo the eight-bit character whose value is the octal value ooo
\xXX  the eight-bit character whose value is the hexadecimal value XX  
\cca control-c character

The result is single-quoted, as if the dollar sign had not been present.

 echo $'\a12\bAB'

Beep is sounded, 12 is displayed, a backspace positions at the 2
then the A is placed over the 2, obscuring the 2, then a B is displayed, resulting in 1AB.

To prevent the shell from processing the \ escape it with a leading \
( i.e. echo \\a12\\bAB ).

To sound the alert tone:

echo $'\a'
To bold part of a message it is necessary to use the ANSI terminal control sequence :
echo ++++ The message  $'\e[1m'  mds[]: "(/)(Warning)"   $'\e[0m' does not belong in alert 
     ++++ The message mds[]: (/)(Warning) does not belong in alert.log

   See ANSI terminal codes for additional renditions.
It may be helpful to create a file containing only the ESCape character by:

echo -n $'\e' > ESC


The ` character encloses a command and is not a quoting character.
> export startedAt=`date +%s`  # (seconds since epoch usable to calculate elapsed seconds at completion or in .bash_logout.
> echo $startedAT

Locale-Specific Translation

A quoted string preceded by $ will cause the string to be translated according to the current locale,
Perhaps format dependent on formats prefered by specific countries, or language.( for example

If the current locale is C or POSIX, the dollar sign is ignored.
If the string is translated and replaced, the replacement is quoted.

example: echo $LOCALE QQ(_) eh wot?


Simple Commands

A sequence of words separated by spaces, terminated by a control operator which returns a status.

The first word generally specifies a command to be executed followed by arguments (options, files, etc).
For example to list the files in the current directory in long format:

 ls -l 
 total 88
-rwxr-xr-x    1 realger1 realger1    11747 Nov 14 19:47 a.out
-rw-r--r--    1 realger1 realger1      211 Nov 14 19:24 buff.c
-rw-r--r--    1 realger1 realger1      591 Nov 14 19:52 buff.s
-rw-r--r--    1 realger1 realger1        0 Oct 11 17:49 lx
drwx------    2 realger1 realger1     4096 Oct 30 01:42 logs
-rw-r--r--    1 realger1 realger1        0 Oct 13 15:49 lynx.cfg 

Multiple commands may be on a single line seperated by ; or on seperate lines.

Control Operators

Commands separated by a ; are executed sequentially; the shell waits for each command to terminate.
This is the same as having commands on seperate lines, i.e. terminated by a newline.
The status is that of the last command executed.


When a command ends with &, the shell executes the command asynchronously in a subshell, i.e. the shell does not wait for the command to finish. A command prompt is issued immediately.
Known as executing the command in the background. The status is 0 .
The standard input for asynchronous commands is /dev/null by default.
$! contains the pid of that background process and can be assigned with back_PID=$!, then wait back_PID will wait until the background process completes.


A sequence of simple commands separated by |.
The STDOUT of each command is sent to the STDIN of the next command.
For example to cut off the type, mod bit display, links, owner and group columns from the ls -l (i.e. the first 34 characters ) use:
ls -l  |  cut -c35-
   11747 Nov 14 19:47 a.out
     211 Nov 14 19:24 buff.c
    4096 Oct 30 01:42 logs

The shell waits for each of the commands in the pipeline to complete, unless the pipeline is to be executed asynchronously .
Each command is executed in its own subshell .
The status is that of the last command or its negation if  !|.

The next command may be on a subsequent line, this permits comments after the pipe for example:
ls -l | #list the files
cut -c35-

Lists of Commands

A list is a sequence of one or more pipelines separated by one of the operators
&&     ||     ;     &     terminated by     ;     &   or a newline.

&& and || have equal precedence, followed by ; and & which have equal precedence.

Compound Commands


Looping Constructs

Use break as target of an if to terminate a loop prematurely.


for name [ in words ] ; do command-list ; done
If in words is omitted, for executes command-list once for each positional
parameter that is set.
The status is that of the last command that executes.
If the expansion of words is an empty list, no commands are executed, and the status is 0̸!
for ODDNUM in 1 3 5 7 ; do  echo $ODDNUM ;done

alternate format:

for (( expr-init ; expr-test ; expr-incr )) ; do command-list ; done 
results not 0 results 0
  • command-list is executed
  • command-list is NOT executed
  • expr-incr is evaluated and
    processing continues with the expr-test
  • processing continues with
    the command after the done.

    A 1 is used if an expr is ommited.

    The return value is the status of the last command in list that is executed, or false if any of the expressions is invalid.



    until test-commands; do commands; done 
    while test-commands
    As long as test-commands has an status which is
    not zero zero
    execute commands
    ps|grep "rsync --progress"
    until [ $RC -ne 0 ] ; do date ;echo zzz;sleep 5;ps|grep --quiet "rsync --progress";RC=$?; done

    The status is the status of the last command executed in commands;


    case $var in
         pattern1  [| patternn] ) command-list ;;
        [patternm             ) command-list ;;]               …

    Execute the command-list corresponding to the first pattern that matches $VAR.
    A pattern list is delimited by | and terminated by ).
    A pattern list and associated command-list is known as a clause. Each clause must be terminated with ;;.
    $var undergoes i
    tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal before matching is attempted.
    pattern undergoes tilde expansion, parameter expansion, command substitution, and arithmetic expansion.

    The code:
    echo "Enter the name of an animal:"
    read ANIMAL
    echo "The $ANIMAL has "

    case $ANIMAL in
     horse | dog | cat) echo four ;;
     man | kangaroo   ) echo two ;;
     *                ) echo an unknown number of;;

    echo "legs."
    running code
     Enter the name of an animal:
    The cat has
    The status is 0̸ if no pattern is matched.
    Otherwise, the status is the status of the command-list executed. (Which might be zero!)
    As is often the case in this documentation, this definition is not precise or complete. For exact syntax look elsewhere!

    if test ; then true command-list; fi

    test (aka conditional expressions) is evaluated or
    commands aare executed. A true or success result returns and causes the true-command-list to be executed.
    (Some languages use for false. Using for success proivides for multiple failure return codes.)

    if test

    When test and action are short this can be written on a single line:
    if test; then  true-commands;  more-true-commands; fi


    generates menus.

    select name [in words]; do commands; done

    1. The list of words is expanded, generating a list of items.
    2. These items are output to standard error output stream, each preceded by a number. If the in words is omitted, the positional parameters are output, as if in "$@" had been specifed.
    3. The PS3 prompt is then displayed and a line is read from the standard input.
    4. If the line consists of a number corresponding to one of the displayed words, then the value of name is set to that word. If the line is empty, the words and prompt are displayed again.
    5. Other values causes name to be set to null.
    6. If EOF is read, the select command completes. The line read is saved in the variable REPLY.
    7. The commands are executed after each selection until a break or return command is executed, at which point the select command completes.


    Group commands for later execution, using a name, in the current shell context (no new process is created) frequently with different targets or operations as specified by arguments.

    Declared using :

    function funcname (){
    return [rc];
    The command-list is executed when funcname is used as a command.

    Functions can be defined within a script or in a file but must be defined before they are invoked.
    To include a file containing functions use   source fileWithFuncs  or   . fileWithFuncs.
    A function is invoked as if it were a commmand, for example:

     > pwd
     > funcname arg1 arg2 … # no ()s are used.
     > date $1
    When a function is entered, the positional parameters are the arguments of the caller
    and number of positional parameters ($#) is the number of arguments. $0 ( script name ) is unchanged.

    The status of a function is the status of the last command executed in the command-list or the value supplied by return n.
    When the function completes,

    Variables local to the function may be declared with the local builtin making them accessible only to the function and the commands it invokes.

    Functions may be recursive. No limit is placed on the number of recursive calls.


     > echo $0
     > cat 
     echo $0
     echo $1
     if [ -e $1 ]; then rm $1;fi
     touch $1
     chmod 755 $1
    > .
    > resetFile  output1
    -bash                 notice that 0̸ reflects the caller of the script not the function 
    >ls -l output1
    -rwxr-xr-x 1 me mygroup 0 Oct  7 13:21 0

    Parameters and VARIABLES

    A parameter stores values.
    It can be referenced by prefixing it with a $ and can be a name ($HOME, $LOGNAME, $PATH), a number ($1), or one of several special characters .
    A parameter is 'set' if it has been assigned a value (the null string is a valid value).

    A variable is a parameter denoted by a name. A variable may be assigned by a statement of the form


    If value is not given, the variable is assigned the null string.
    All values undergo tilde expansion, parameter expansion, and variable expansion, command substitution, arithmetic expansion, and quote removal .

    Once a variable is 'set', it may be 'unset' only by using the unset builtin.

    Positional Parameters

    A positional parameter is a parameter denoted by $ and one or more digits assigned from the shell's arguments when a script or function is invoked.
    They may be reassigned using set , but not with assignment statements.
    Positional parameter $N may be referenced as ${N}.
    They are temporarily replaced when a function is executed .

    A positional parameter consisting of more than a one digit must be enclosed in braces.

    To test if the first positional parameter was provided and is an existing file use:
    if [  ! -e  ${1:? What file\?} ]; then echo \ \-\- $1 does not exist; exit 2; fi
    shift causes the 1st parameter to be assigned to $0, the 2nd assigned to $1

    Special Parameters

    $0 name of the shell or calling script.
    If Bash is invoked with a file of commands (see Shell Scripts), $0 is set to the name of that file.
    If Bash is started with -c (see Invoking Bash), then $0 is set to the first argument after the string to be executed    otherwise, it is set to the filename used to invoke Bash, as given by argument zero.
    $* all positional parameters, starting from 1 (0 is the name of the caller).

    Within double quotes, $* expands to a single word with the value of all the parameters joined by the first character of the IFS special variable.
    That is, $* is equivalent to "$1c$2c…", where c is the first character of IFS.
    (IFS cannot be displayed as a variable with echo $IFS).

    set|grep IFS|hexdump -C
    00000000  49 46 53 3d 24 27 20 5c  74 5c 6e 5c 43 2d 40 27  |IFS=$' \t\n\C-@'|
    00000010  0a                                                |.|
    If IFS is unset, the parameters are separated by spaces.
    If IFS is null, the parameters are joined without intervening separators.
    $# number of positional parameters.
    $# is 3 for scriptName a b c
    $# is 1 for scriptName "a b c"
    $@ parameters are presented as separate words.
    $@ is equivalent to "$1" "$2" ….
    When there are no positional parameters, "$@" and $@ are ignored.
    $? status of the most recently executed foreground pipeline.
    N.B. As an arithmetic item, i.e. use:   if [ $? -gt 0 ]; then ... to test.
    $- current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option).

    himBH i.e. hashall,?,monitor, braceexpand, histexpand

    $$ process ID of the shell. In a ( command,…) subshell, it is replaced with the process ID of the invoking shell, not the subshell.
    $!process ID of the most recently executed background (asynchronous) command.
    $_Initally set to the absolute filename of the shell or shell script being executed as passed in the argument list.
    Subsequently, set to the last argument to the previous command, after expansion.
    Also set to the full pathname of each command executed and placed in the environment exported to that command.
    When checking mail holds the name of the mail file.



    Input and Output

    The basic concept that utilities are filters and accept data from another utility and pass it to yet another is facilited through the use of reading from stdin aka file descriptor 0, writing to stdout (descriptor 1). and control/diagnostic &helip; output to stderr)(descriptor 2) The shell uses the | between to filters to indicate that the stdout from the previous filter is sent directly to the next filter (i.e. no file is created).
    For examle:
    ls | grep middlechars


    A command's input and output may be redirected with < (input) and > (output). Redirection opens and closes files before the command is executed and a failure causes the command to be skipped. For example sudo will not execute if the output is redirected to a file that is not writable to the invoking user.

    Processed from left to right they may precede, appear within or follow a command and are commonly placed after a command where the appearance is consistant with the dataflow.
    For example:

    sort < infile > outfile
    The filename following the redirection operator is subjected to { brace, ~ tilde, ${ parameter, $(( arithmetic and filename* expansion, ` command substitution and ' " quote removal.

    If it expands to more than one word, Bash reports the error: "ambiguous redirect" and the command is not executed.

    Redirecting Input

    Causes filename to be opened for reading.
    Default file descriptor number(n) is 0, standard input.
     tr '[:upper:]' '[:lower:]' < cedar2.txt

    Redirecting Output


    If filename does not exist it is created.
    If filename exists it is truncated to zero size, use [n]>>filename to append to an exisiting file.
    if filename exists as a regular file and noclobber is set, the command is not executed, Use >| to overwrite filename regardless of noclobber.

    If the directory for filename does not exist; the command is not executed and the error No such file or directory is output .

    Default output file descriptor n is 1 standard output. Use 2 for standard errror.
    To redirect stdout to stderr use  1>&2.

    Although any file descriptor number can be used by a program I've never seen anything else.(ed)

    Programs that output 2 reports or read multiple input file streams usually with arguments like:
     invoices --transin --checkin --summary summ.txt --details details.txt

    Example: ls -l > filelist 2>>err.log # redirects STDOUT to filelist and STDERR to err.log

    NB: It's the shell (not the program) that (attempts to) delete and open the destination file.
    This is especially important for sudoers since if your current user id cannot create/write to the redirected file, the command fails.

    if current directory is /var/log

     ls -l > t   will (as you should expect) fail unless you have write access to /var/log!

     sudo -l > t   will also fail (although you might not expect that)

     sudo touch t   will sucessfully create an empty file, next
     sudo chown myuser t   will change the owner
     sudo -l > t   STILL FAILS (since myuser does not have write access to the directory /var/log in order to delete/create a file)
     sudo -l >> t   will work since myuser is the owner of the existing file which is being appened to.

    Redirecting stderr while leaving stdout as redirected in command line:

    The function:

    sed "s/xy/as/" <$1 
    ls -l $1 }
    Invoked with sedlist infile > outfile causes sed to operate on infile and errors go to the console.

    Redirecting both STDOUT and STDERR

       command  &>filename

    ls -l &> /tmp/stdout+stderr

    Redirecting to /dev/null should be avoided. Instead use, for example:

    monthlyProcessing > monthly.rpt 2> monthly.err
    if [ $? > 0 | -e monthlyReport.err ] ; then echo " -- Error:"; cat monthlyReport.err

    This displays the STDERR output if the return code was not 0 or the file STDERR was redirected to exists.

    Duplicating File Descriptors

    duplicate input file descriptors:  [n]<&fdes

    If n is not specified, the STDIN (file descriptor 0) is used. If fdes expands to one or more digits, the file descriptor (n) becomes a copy of that file descriptor.
    If the digits in fdes do not specify a file descriptor open for input, a redirection error occurs.
    If fdes evaluates to -, file descriptor n is closed.

    Duplicate output file descriptors: [n]>&fdes
    If n is not specified, the standard output (file descriptor 1) is used. If the digits in fdes do not specify a file descriptor open for output, a redirection error occurs. As a special case, if n is omitted, and fdes does not expand to one or more digits, STDOUT and STDERR are redirected .

    Moving File Descriptors

    Move the file descriptor d to file descriptor n, or the standard input if n is not specified: [n]<&d-

    d is closed after being duplicated to n.

    Opening File Descriptors for Reading and Writing

    causes file to be opened for both reading and writing on file descriptor n, or on file descriptor 0 if n is not specified.
    If the file does not exist, it is created.

    Here Documents

    Read the current source as STDIN up to a line containing only delimiterWord.
    The format is:
    lines of input


    No trailing spaces are permitted on the line with delimiterWord

    No parameter expansion, command substitution, filename expansion, or arithmetic expansion is performed on delimiterWord.
    If any characters in delimiterWord are quoted, the delimiterWord is the result of quote removal on delimiterWord, and the lines in the here-document are not expanded.
    If delimiterWord is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion.
    The pair \newline is ignored, and \ must be used to escape \, $, and `.

    <<- leading tab characters are stripped from input and the line containing delimiter. This allows here-documents within shell scripts to be indented.

    > cat << ++++ > newfile 
          here is an input line
      and another
    These come from the script $0 with args $*
    Current \$PATH is $PATH
    > cat newfile
        here is an input line
    and another
    These come from the script -bash with args editing-mode vi 
    Current $PATH is usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin 

    Executing Commands

    Simple Command Expansion

    When a simple command is executed, the shell performs the following operations from left to right.

    1. Expanions are performed.
    2. The first word is taken to be the name of the command and the remaining words are the arguments.
    3. Redirections are performed
    4. The text after the = in each variable assignment undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal before being assigned to the variable.
      variable=`ls ~/*.sh`
      /Users/me > echo $variable
      /Users/me/ /Users/me/ /Users/me/

      If no command name results, the variable assignments affect the current shell environment. Otherwise, the variables are added to the environment of the executed command and do not affect the current shell environment.

      If no command name results, redirections are performed, but do not affect the current shell environment.

      If there is a command name left after expansion, execution proceeds as described below. Otherwise, the command exits.

      If one of the expansions contained a command substitution, the status of the command is the status of the last command substitution performed. If there were no command substitutions, the command exits with a status of 0̸.

    Command Search and Execution

    After a command has been split into words, if it results in a simple command and an optional list of arguments, the following actions are taken.
    If the command name contains no slashes, the shell attempts to locate it checking for a:

    1. function
    2. builtin
    3. element of $PATH for a directory containing an executable file.
      (Bash uses a hash table to remember the full pathnames of executable files to avoid multiple PATH searches (see the description of hash in section Bourne Shell Builtins, this may be a problem if the file is created during the shell execution. A full search of the directories in $PATH is performed only if the command is not found in the hash table. )
      If the search is unsuccessful, the shell outputs an error message and returns an status of 127.
    4. If the search is successful, or if the command name contains one or more slashes,
      the shell executes the named program in a separate execution environment.
      Argument 0̸ is set to the name given, and the remaining arguments to the command are set to the arguments supplied.
    5. If this execution fails because the file is not in executable format, and the file is not a directory, it is assumed to be a shell script and the shell executes it as described in section Shell Scripts.
    6. The shell waits for the command to complete and collects its status, unless the command was begun asynchronously using the &

    The status of a simple command is its exit status or 128+n if the command was terminated by signal??(_) n.

    Command Execution Environment

    When a simple command other than a builtin or shell function is to be executed,(among other things ) it is invoked in a separate execution environment that consists of:

    A command invoked in this separate environment cannot affect the calling shell's execution environment.

    Command substitution and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment, except that traps caught by the shell are reset to the values that the shell inherited from its parent at invocation.

    Builtin commands that are invoked as part of a pipeline are also executed in a subshell environment.
    Changes made to the subshell environment cannot affect the shell's execution environment.


    When a program is invoked, an array of strings ( NAME=value pairs) and environment is made available.

    On invocation, the shell marks each parameter export to child processes.
    Executed commands inherit the environment.
    unset, export and declare add/delete parameters and functions to/from the environment.

    The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described in Shell Parameters.
    These assignment statements affect only the environment seen by that command.

    With -k aka -o keyword (a set builtin), parameter assignments are placed in the environment for a command, not just those that precede the command name.

    When Bash invokes an external command, $_ is set to the full path name of the command.

    status $?

    0 command has succeeded.

    A non-zero status indicates failure.
    This seemingly counter-intuitive scheme is used so there is

    128+n command failed with a return code of n
    127 command is not found.
    126 command is found but is not executable (check x flag in mode with ls -l).
        1 command failed because of an error during expansion or redirection ( ex: unwritable destination )
        2 builtins: incorrect usage. (syntax error)
    Other values < 126 indicate specific errors assigned by the script/command.
        9 perl compilation failed.
    258 bash encountered a syntax error.
    130 find
    131 find

    The status is used by the Conditional Constructs and some of the list constructs .

    A negative value used in an exit returns 256-value example exit -9 returns 247

    Signals Handled by bash

    See trap for prempting signals for a script.

    see stty
    > stty -a
    cchars: discard=^O; dsusp=^Y; eof=^D; eol=;
        eol2=; erase=^?; intr=^C; kill=^U; lnext=^V;
        min=1; quit=^\; reprint=^R; start=^Q; status=^T;
        stop=^S; susp=^Z; time=0; werase=^W;
    intr=^C; quit=^\; killcharacters typedAhead=^U; eof=^D; eol=<undef> eol2=; swtch=; start=^Q; stop=^S; susp=^Z; rprnt=^R;
    SIGQUIT^\ ignored.
    SIGTERM^c ignored when Bash is interactive, in the absence of any traps,
    kill TERM p does not terminate an interactive shell
    SIGINT^ccaught and handled (so that wait is interruptible) and
    bash breaks out of any loops.
    Ignored by asynchronous commands
    ignored if Job Control is in effect.
    ignored for commands run as a result of command substitution
    SIGHUP Causes the shell to exit by default. Before exiting, all job are sent SIGHUP .
    Stopped jobs are first sent SIGCONT to ensure that they receive the SIGHUP.
    To prevent the shell from sending the SIGHUP signal to a particular job, it should be removed from the jobs table with disown (see Job Control) or marked to not receive SIGHUP using disown -h.

    If huponexit is set bash sends SIGHUP to all jobs when an interactive login shell exits.

    If BASH receives a signal, for which a trap has been set, while waiting for a command to complete, will not be executed until the command completes.
    If waiting for an asynchronus command a status greater than 128 is set, then trap is executed.

    Commands started by Bash have signal handlers set to the values inherited by the shell from its parent.

    Additional signals , passed to process

    Shell Scripts

    A file containing shell commands.
    Bash reads and executes commands from the file, then exits.
    This mode of operation creates a non-interactive shell.
    Used as the option argument when invoking Bash, and neither -c nor -s is supplied (see Invoking Bash).

    The parameter $0 is set to the name of the file (rather than the name of the shell),
    and positional parameters are set to the remaining arguments, i.e. $1, $2 ….

    When a file in the $PATH for a command, it spawns a subshell to execute it. In other words, executing

    file arguments
    is equivalent to executing
    bash file arguments

    See chmod regarding setting permissions to allow a file to be executable as a script.

    This subshell initializes itself, so that the effect is as if a new shell had been invoked to interpret the script,
    with the exception that the locations of commands remembered by the parent (see hash Builtins) are retained by the child.

    If the first line of a script begins with #!, the remainder of the line specifies an interpreter for the the script, followed by the arguments.

    For example:


    #!/usr/bin/perl -w