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 " preserves character's literal values, with the exception of $ , `, and \ .
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
\\ backslash
\' single quote
\a alert (bell) x07
\b backspace x08
\n newline x0A
\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

A new-line character is \n or \013 or \x0A or \cJ (i.e. ctrl-J )
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.

An alternate method is to prevent the shell from processing the \ by escaping it with another \
( i.e. echo \\a12\\bAB ).

To sound the alert tone:

echo $'\a'

To bold part of a message:

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 double-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 double-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 .
The standard input for asynchronous commands is /dev/null in the absence of any explicit redirections.
$! contains the pid of that background process and can be assigned with back_PID=$!.
A subsequent 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.

An AND list has the form: command1 && command2
if command1 returns a status of ; then command2 is executed.
try_to_do_stuff && do_more_stuff_since_it_is_going_well

An OR list has the form: command1 || command2
If command1 returns a non-zero status; then command2 is executed.
try_to_do_stuff || clean_up_mess_from_failured_stuff

The status is that of the last command executed.

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
  • processing continues with
    the command after the done.
  • expr-incr is evaluated and
    processing continues with the expr-test
  • 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 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

    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 exists it is truncated to zero size.
    if filename exists as a regular file with noclobber set the command is not executed .
    Using >| overwrites the file regardless of noclobber.

    Default output file descriptor n is 1, standard output; 2 is standard errror.

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

    Use ;  [n]>>filename to append to an exisiting file.

     ls -l > filelist 2>>err.log

    Redirecting stderr while leaving stdout as redirected in command line:

    sed "s/xy/as/" <$1 
    ls -l $1  >&2
    Invoked with sedlist infile > outfile will have the ls -l 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:

     command > /tmp/$$.1 2> /tmp/$$.2 
    if [ $? > 0 | -e /tmp/$$.2 ] ; then echo " error \n"; cat /tmp/$$.2

    which will display the STDERR output if there is an error. unix filters (nearly every command/program/script is a filter) take their input from STDIN (aka file descriptor 0 ) and write their output to STDOUT (descriptor 1). They also write control/diagnostic... output to STDERR (descriptor 2)

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

    How do programs write out 2 reports or read multiple input file streams? Usually with arguments like:

    invoices --transin --checkin --summary summ.txt --details details.txt 

    Regarding appending or creating a new file(deleting the existing one first) :

    NB: It's the shell (not the program) that (attempts to) open the files, and perhaps delete the existing file>>

    This is specially important for sudoers since if your current user id cannot create/write to /var/log/t,
    if current directory is /var/log

    ls -l > t
    will (as you should expect) fail!
    sudo -l > t
    will also fail (although you might not expect that)
    sudo touch t
    will sucessfully create an empty file, next
    sudo chown dgerman t
    will change the owner
    sudo -l > t
    STILL FAILS (since dgerman does not have write access to the directory /var/log in order to delete/create a file)
    sudo -l >> t
    will work since dgerman is the owner of the existing file which is being appened to.

    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 

    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.

    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 $?

    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.

    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


    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.

    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