table of contents,

There exists a January 19, 2015 version at

Basic Shell Features

Shell Operation

  1. Reads 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 return status.
   # causes remaining characters on that line to be ignored

 Metacharacters are: | & ; ( ) < > [space] and [tab] .


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 their literal values, with the exception of $ , `, and \ .

ANSI-C Quoting

A word of the form $'string' expands to string, with backslash-escaped characters replaced with
\b backspace x08 \\ backslash
\n newline x0A \r carriage return x0D
\t horizontal tab x09 \f form feed x0C
\v vertical tab x0B \a alert (bell) x07
\' single quote
\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.


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 blanks, 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
produces the output:

 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 return 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. Known as executing the command in the background.
The return status is 0 .
A command prompt is issued immediately
The standard input for asynchronous commands is /dev/null in the absence of any explicit redirections.


A sequence of simple commands separated by |.
Pipelines are one of the most power features of unix shells.
The stdout of command on the left side is sent to the STDIN of the command on the right side.
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-
produces the output:
  11747 Nov 14 19:47 a.out
     211 Nov 14 19:24 buff.c
     591 Nov 14 19:52 buff.s
       0 Oct 11 17:49 lx
    4096 Oct 30 01:42 logs
       0 Oct 13 15:49 lynx.cfg
      11 Dec 19  2004 www -> public_html

The shell waits for each of the commands in the pipeline to complete, unless the pipeline is to be executed asynchronously .

Each command in a pipeline is executed in its own subshell .
The return status of a pipeline is the return status of the last command in the pipeline unless
 ! precedes the pipeline, then return status is the negation of the return status of the last command.

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.

 && AND list
 || OR list.

An AND list has the form: command1 && command2
if command1 returns an return status of zero; 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 return status; then command2 is executed.
try_to_do_stuff || clean_up_mess_from_failured_stuff

The return status of AND lists and OR lists is the return status of the last command executed.

Compound Commands


Return a status of 0 or 1 depending on the evaluation of the conditional expression.

Looping Constructs


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 return status is the exit status of the last command that executes.
If the expansion of words is an empty list, no commands are executed, and the return 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 return 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 return status which is
    not zero zero
    execute commands
    ps|grep "rsync --progress"
    until [ $RC != 0 ] ; do date ;echo zzz;sleep 5;ps|grep --quiet "rsync --progress";RC=$?; done

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


    case word in [ [(] pattern1  [… | patternn] ) command-list ;;] esac

    selectively execute the command-list corresponding to the first pattern that matches word.
    The | is used to separate multiple patterns, and the ) operator terminates a pattern list.
    A list of patterns and an associated command-list is known as a clause.
    Each clause must be terminated with ;;.
    word 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.
    There may be an arbitrary number of case clauses, each terminated by a ;;.
    The first pattern that matches determines the command-list that is executed.

    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 return status is 0 if no pattern is matched.
    Otherwise, the return status is the return status of the command-list executed. (Which might be zero!)



    if test; then  true-commands;  more-true-commands; fi
    Frequently written multi line (but why?)
    if tests
    For example:
    rm xxyyww; rc=$?;
    if $rc ; then echo " failed \$RC=$rc"; exit $rc; fi
    else - if
    [ else false-commands; ]
    if tests; then
      elif more-tests; then
      [else false-commands;]

    tests are executed, then upon a return status of

  • zero, the true-command list is executed.

  • non-zero each elif list is executed in turn,
      and if its return status is zero, the corresponding more-true-commands is executed
    and the command completes.

    If "else false-commands" is present, and the final command in the final if or elif clause has a non-zero return status,
    then false-commands is executed.

    The return status is the return status of the last command executed, or zero if no condition tested true.

    if [ $RC -ne 0 ]; then echo myscript failed return status= $RC ; fi

    if [ $? -eq 0 ]; then echo yourscript worked, no cleanup needed; exit; fi

    if [ $anyDefinedVarilable ]; then echo true ; fi ( including $? )

    if [ -z "$PS1" ]; then
    echo This shell is not interactive
    else echo This shell is interactive

    The very simple (but not as clear)
    If first command works, execute second command

    ./ && ./

    If first command fails, execute second command

    ./checkIt || { echo "checkIt failed" ; exit 1; }

    (see Lists of Commands )


    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 printed on the standard error output stream, each preceded by a number. If the in words is omitted, the positional parameters are printed, 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 ] func () { command-list; }

    The reserved word function is optional, if supplied the parentheses are optional.
    The command-list is executed when func is specified as the name of 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

    . fileWithFuncs

    A function is invoked as if it were a commmand, that is funcname arg1 agr3 … no ( ) are used.

    When a function is entered, the arguments are the positional parameters.
    The number of positional parameters ($#) indicates the number of arguments. Positional parameter $0 is unchanged.

    The return status of a function is the return status of the last command executed in the command-list or the value supplied by return n.
    When the function completes, execution resumes with the command after the function call, the values of the positional parameters and the $# are restored

    Variables local to the function may be declared with the local builtin making them are 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
    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. ($0 is a 'Special' parameter.)
    Positional parameters are assigned from the shell's arguments when it is invoked, and
    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 .

    When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces.

    Special Parameters

    May only be referenced; assignment to them is not allowed.
    $* positional parameters, starting from 1.
    When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable.
    That is, $* is equivalent to "$1c$2c...", where c is the first character of the value of the IFS variable.
    If IFS is unset, the parameters are separated by spaces.
    If IFS is null, the parameters are joined without intervening separators.
    $@ parameters are presented as separate words.
    $@ is equivalent to "$1" "$2" ….
    When there are no positional parameters, "$@" and $@ are ignored.
    $# number of positional parameters
    $? return 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.
    $0 name of the shell or shell 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, if one is present,    otherwise, it is set to the filename used to invoke Bash, as given by argument zero.
    $_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.



    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 not to be executed. 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, filename expansion, command substitution and quote removal, but if it expands to more than one word, Bash reports an 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.
    Example: tr '[:upper:]' '[:lower:]' < cedar2.txt

    Redirecting Output

    If filename exists it is truncated to zero size.
    Redirection using > to an existing regular file with noclobber set will cause the command not to be executed .
    Using >| overwrites the file regardless of noclobber.

    Appending Redirected Output

    Default file descriptor n is 1, standard output, 2 is standard errror.
    ls -l > filelist 2>>err.log

    If the directory filename is to be created in 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.

    Redirecting both STDOUT and 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 considered a filter) take their input from STDIN (aka file descriptor 0 ) and write their output to STDOUT (aka file descriptor 1). They also write control/diagnostic... output to STDERR (aka file descriptor 2)

    Although any file descriptor number can be used by a program I've never seen anything else.
    So how do programs write out 2 reports or read multiple input file streams? Usually with agreement like

    invoices --transin --checkin --summary summ.txt --details details.txt --transout t.out
    Regarding appending the STDERR/STDOUT 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 and you try:

    ls -l > t it 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 /var/log directory 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 input from the current source until a line containing only word (with no trailing blanks) is read.
    All of the lines read up to that point are then used as the STDIN for a command.
    The format is:
    lines of input


    No parameter expansion, command substitution, filename expansion, or arithmetic expansion is performed on word.
    If any characters in word are quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded.
    If word 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 quote the characters \, $, and `.

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

    cat newfile << ++++
        here is an inpuit line
        and another

    Duplicating File Descriptors


    duplicates input file descriptors.
    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.

    [n]>&fdes duplicates output file descriptors.
    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

    The redirection operator


    moves the file descriptor d to file descriptor n, or the standard input if n is not specified.
    d is closed after being duplicated to n.


    moves the file descriptor d to file descriptor n, or the standard output ifd is not specified.

    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/pocketForCordury.shA

      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 return status of the command is the exit status of the last command substitution performed. If there were no command substitutions, the command exits with a status of zero.

    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 return 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 return status, unless the command was begun asynchronously using the &

    The status of a simple command is its return status as provided by the POSIX.1 waitpid function, 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.

    return status

    0 command has succeeded.
    A non-zero return status indicates failure.
    This seemingly counter-intuitive scheme is used so there is
  • one well-defined way to indicate success and
  • a variety of ways to indicate various failure.
    128+n command terminated on a fatal signal whose number is n
    127 command is not found.
    126 command is found but is not executable.
    If a command fails because of an error during expansion or redirection, the return status is greater than zero.

    9 perl compilation failed.
    2 builtins: incorrect usage.

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


    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=^\; kill=^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, the trap will not be executed until the command completes.
    If waiting for an asynchronus command an return 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 special parameter $0 is set to the name of the file (rather than the name of the shell),
    and the positional parameters are set to the remaining arguments, i.e. $1, $2 ….

    When Bash finds such 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 permissionsi 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 the description of hash in Bourne Shell 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