# Canonical source: http://blackskyresearch.net/shelltables.txt
# Maintained by Isaac (.ike) Levy and contributors.
# A 20+ year empirical verification corpus -- features that proved
# non-portable across production UNIX and Linux systems have been removed.

--------------------
Shell Metacharacters

>     `prog >file` direct standard output to file, (over-writes file)
>>    `prog >>file` append standard output to file
<     `prog <file` take standard input from file
|     `p1 | p2` connect standard output of p1 to standard input of p2
<<str  here document: standard input follows, up to next str on a line by 
       itself, one way to represent a multiline string
*      match any string of zero or more characters in filenames (a glob
       expansion, not a regex)
?      match any single character in filenames
[ccc]  match any single character from ccc in filenames; ranges
       like 0-9 or a-z are legal
;      command terminator: `p1;p2` does p1, then p2
&      like ; but doesn't wait for p1 to finish
`...`  (grave/backtick)      run command(s) in ...; output replaces `...`
(...)  run command(s) in ... in a sub-shell
{...}  run command(s) in ... in current shell (rarely used)
$1, $2 etc.    $0...$9 replaced by positional arguments to shell file
$var   value of shell variable var
${var} value of var; avoids confusion when concatenated with text
\       \c take character c literally, \newline discarded
'...'   take ... string literally
"..."   take ... string literally after $, `...` and \ interpreted


-------------------------------
Redirection Operators — Full Set

> file       stdout (fd 1) to file.  Create or truncate.
>> file      stdout to file.  Create or append.
< file       stdin (fd 0) from file.
<< word      here document.  See Here Documents below.

2>file       stderr (fd 2) to file.
2>>file      stderr to file, append.
2>&1         stderr to wherever stdout currently goes.
>&digit      duplicate fd digit onto stdout.
<&digit      duplicate fd digit onto stdin.
<&-          close stdin.
>&-          close stdout.
N>file       fd N to file (any digit 0-9).
N>&M         fd N to wherever fd M goes.

ORDER MATTERS.  Evaluated left to right:

  cmd >file 2>&1     CORRECT: both stdout and stderr to file.
                     (stdout → file, then stderr → stdout)
  cmd 2>&1 >file     USUALLY WRONG: stderr to terminal, stdout to file.
                     (stderr → stdout [still terminal], then stdout → file)

exec (no command) changes the shell's own fds permanently:

  exec 3>&1          save stdout on fd 3
  exec 1>/dev/null   silence stdout
  exec 1>&3          restore stdout
  exec 3>&-          close fd 3

/dev/null discards output, returns EOF on read:

  cmd >/dev/null 2>&1     silence everything
  cmd 2>/dev/null         silence errors only


--------------
Here Documents

A here document feeds multi-line text to a command's stdin.
The delimiter can be any word.  The document ends when the
delimiter appears alone on a line.

  Unquoted delimiter — expansions happen inside:

    cat << EOF
    Hello ${USER}, your home is ${HOME}.
    Today is $(date).
    EOF

  Quoted delimiter — no expansion, text is literal:

    cat << 'EOF'
    This is literal text.
    ${USER} is not expanded.  $(date) is not run.
    \047 is four characters, not a single quote.
    EOF

  The quoted form is shell's multi-line literal string — the
  closest equivalent to Python's triple-quoted '''string'''.

  Indented form — <<- strips leading TABS (not spaces):

    if [ "${verbose}" ] ; then
    	cat <<- EOF
    	indented text here
    	still indented
    	EOF
    fi

  Note: <<- strips only hard tabs.  Spaces are preserved.
  Editors that convert tabs to spaces will break this form.

When to reach for a here document:

  - Multi-line output: prefer heredoc over repeated printf or
    echo calls.  The text is editable as text, not as code.
  - Generating files: heredoc into a redirect (cat << 'EOF' > file)
    is cleaner than a sequence of echo/printf calls.
  - Templates with no expansion: quoted delimiter means no quoting
    headaches inside the body.  No escaping needed.
  - Editing under pressure: in ed(1) or a minimal editor, a heredoc
    is lines of text.  Repeated function calls are lines of code.
    One is prose.  The other is program structure.


--
$#     Provides the total number of arguments passed to the shell program or function.
$*, $@ Represents all the command-line arguments at once.
"$*"   Represents all the command-line arguments as a single string.
"$@"   Represents all the command-line arguments as separate, individual strings.


------------------------------
POSIX built-in shell variables (preceded by $, e.g. "$#")

#     Number of arguments given to current process.
@     Command-line arguments to current process. Inside double quotes, expands
      to individual arguments.
*     Command-line arguments to current process. Inside double quotes, expands
      to a single argument.
-     (hyphen) Options given to shell on invocation.
?     Exit status of previous command.
$     Process ID of shell process.
PPID  Process ID of parent process.
!     Process ID of last background command. Use this to save process ID numbers
      for later use with the wait command.
0     (zero) The name of the shell program, in most cases, including full
      invocation path.
PWD   Current working directory, containing no components of type symbolic link,
      no components that are dot, and no components that are dot-dot when the
      shell is initialized.
ENV   Used only by interactive shells upon invocation; the value of $ENV is
      parameter-expanded. The result should be a full pathname for a file to
      be read and executed at startup. Suppressed in privileged mode
      (euid != uid).
HOME  Home (login) directory.
IFS   Internal field separator; i.e., the list of characters that act as word
      separators. Normally set to space, tab, and newline.
LANG  Default name of current locale; overridden by the other LC_* variables.
LC_ALL     Name of current locale; overrides LANG and the other LC_* variables.
LC_COLLATE   Name of current locale for character collation (sorting) purposes.
LC_CTYPE     Name of current locale for character class determination during
             pattern matching.
LC_MESSAGES  Name of current language for output messages.
LINENO    Line number in program or function of the line that just ran.
NLSPATH    The location of message catalogs for messages in the language given
           by $LC_MESSAGES (XSI).
PATH Search path for commands.
PS1  Primary command prompt string. Default is "$ ".
PS2  Prompt string for line continuations. Default is "> ".
PS4  Prompt string for execution tracing with set -x. Default is "+ ".

More POSIX built-ins can be found here (but seriously, don't trust all of them):
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html


-----------------
Exit Status Map

0        success
1-94     errno territory — the kernel's error codes live here.
         A program MAY use these, but risks confusion with errno
         meanings (e.g. exit 2 looks like ENOENT "no such file").
         FreeBSD errno: 0-94.  macOS errno: 0-102 (and growing).
95-125   yours — no kernel or shell claim on this range.
         111 is the 3-finger-claw's die() — chosen above the
         highest errno on any platform, below the shell range.
126      shell: command found but not executable
127      shell: command not found
128+N    shell: process killed by signal N (e.g. 141 = SIGPIPE)

In practice: 0 for success, 1 for general failure, 111 for die().
126, 127, and 128+ are reserved by the shell and kernel.  A
program that exits above 125 is indistinguishable from a shell
or kernel condition.


----------------------------------------------
Signal Names and Numbers — portable reference

Use names, not numbers.  Numbers vary across platforms.
kill -10 sends SIGUSR1 on Linux and SIGBUS on FreeBSD/macOS.
Same command, different signal.  Names are the same everywhere.

In programs: kill -s TERM "$pid"    trap 'cleanup' TERM
At the terminal: kill -9 is muscle memory and everyone knows it.
This table is for translating between the two.

  #   Name     Default    Common use / meaning
  1   HUP      terminate  Terminal hangup; daemon reload convention
  2   INT      terminate  Interrupt (Ctrl-C)
  3   QUIT     core dump  Quit (Ctrl-\)
  6   ABRT     core dump  abort(3) — assertion failure
  9   KILL     terminate  Irrevocable — cannot be caught or ignored
  13  PIPE     terminate  Write to pipe with no reader
  14  ALRM     terminate  alarm(2) timer expired
  15  TERM     terminate  Termination request (default kill signal)

  Signals 1-15 are the portable set.  These numbers are the same
  on Linux, FreeBSD, macOS, and most UNIX systems.

  Above 15, numbers DIVERGE across platforms:

                Linux    FreeBSD/macOS
  SIGBUS         7         10
  SIGUSR1       10         30
  SIGUSR2       12         31
  SIGCHLD       17         20
  SIGCONT       18         19 (FreeBSD)
  SIGSTOP       19         17 (FreeBSD)
  SIGTSTP       20         18 (FreeBSD)

  The divergence above 15 is why names exist.  Use them.


------------------------------------
Finding Programs in your environment

which <utility>         Returns the path to the utility if it exists, 
                        heritage from C shell.
command -v <utility>    Returns the path to the utility, -v flag keeps it
                        silent, -V is default behavior.  Very portable.
whereis <utility>       Looks up executable, man page, and source- not based
                        on the current environment.

----------------------------------------------
Shell Variable Expansion

All operators listed here are fully POSIX -- verified portable across
Bourne-lineage shells on all modern UNIX and Linux systems.

$var      Value of var; nothing if var undefined.  ENV variables are, by
          convention, typed all caps.  Lowercase is personal (your login,
          your locals).  Uppercase is what you stand behind when it
          propagates.  (Note: POSIX IEEE Std 1003.1-2017 Ch. 8 reserves
          lowercase ENV names for applications — no one has followed this
          in forty years.  The convention was set by practitioners who bore
          the cost.  Follow the convention, not the spec.)
${var}    Same as $var, useful if alphanumerics follow variable name.

THE COLON DISTINCTION

  Without colon  tests whether the variable is UNSET
  With colon     tests whether the variable is UNSET OR NULL (empty string)

  In practice: the colon forms are almost always what you want.
  Use no-colon forms only when an empty string is a meaningful value.

                     Set & Not Null    Set But Null     Unset
  ${var-word}        use var           use null         use word
  ${var:-word}       use var           use word         use word
  ${var=word}        use var           use null         assign & use word
  ${var:=word}       use var           assign & use     assign & use word
  ${var+word}        use word          use word         use nothing
  ${var:+word}       use word          use nothing      use nothing
  ${var?msg}         use var           use null         error & exit
  ${var:?msg}        use var           error & exit     error & exit


DEFAULT VALUE -- substitute a fallback when the variable is absent

  ${var:-word}   If var is unset or null, expand to word. var unchanged.
                 Purpose: supply a default value.
                 Example: ${timeout:-30}  -> 30 if timeout not set or empty

  ${var-word}    If var is unset but not null, expand to word. var unchanged.
                 Example: ${timeout-30}   -> 30 only if timeout was never set;
                          returns empty string if timeout=""


ASSIGNMENT -- set the variable if absent, then expand it

  ${var:=word}   If var is unset or null, assign word to var and expand.
                 Example: ${count:=0}   sets count to 0 if unset or empty

  ${var=word}    If var is unset but not null, assign word to var and expand.
                 Note: positional parameters ($1, $2, ...) cannot be assigned.


ERROR/ABORT -- halt the program when a required variable is missing

  ${var:?msg}    If var is unset or null, print "var: msg" to stderr and exit.
                 Omitting msg produces: parameter null or not set
                 Example: ${DATADIR:?"DATADIR must be set"}

  ${var?msg}     If var is unset but not null, print message and exit.


ALTERNATE VALUE -- expand to a substitute only when the variable exists

  ${var:+word}   If var is set and non-null, expand to word; otherwise nothing.
                 Purpose: conditional inclusion -- the inverse of ${var:-word}.
                 Example: ${verbose:+-v}  -> "-v" if verbose is set and non-empty

  ${var+word}    If var is set (even if null), expand to word; otherwise nothing.


STRING LENGTH

  ${#var}        Number of characters in the value of var.
                 Example: ${#PATH}  -> character count of PATH


PREFIX AND SUFFIX TRIMMING

  Remove a glob pattern match from the front or back of a string.
  Uses shell glob patterns (* ? [set]) -- not regular expressions.

  The four operators form a grid:

                  shortest match    longest match
    front (#):    ${var#pattern}    ${var##pattern}
    back  (%):    ${var%pattern}    ${var%%pattern}

  Mnemonic: # before % on a keyboard; front of a string before the back.
            single # or % = shortest match; double = longest match.

  path="/home/tolstoy/docs/report.final.txt"

    ${path#*/}     "home/tolstoy/docs/report.final.txt"  front, shortest
    ${path##*/}    "report.final.txt"                    front, longest  (basename)
    ${path%.*}     "/home/tolstoy/docs/report.final"     back,  shortest (strip last extension)
    ${path%%.*}    "/home/tolstoy/docs/report"           back,  longest  (strip all extensions)



-----------------------------------------
POSIX dirname(1) and basename(1) Examples

path           dirname        basename
"/usr/lib"     "/usr"         "lib"
"/usr/"        "/"            "usr"
"usr"          "."            "usr"
"/"            "/"            "/"
"."            "."            "."
".."           "."            ".."

Command                Results
dirname /              /
dirname //             / or //
dirname /a/b/           /a
dirname //a//b//       //a
dirname                Unspecified
dirname a              . ($? = 0)
dirname ""             . ($? = 0)
dirname /a             /
dirname /a/b           /a
dirname a/b            a




-------------------------------
Subshell and code block summary

Construct   Delimiters  Separate Process  Recognized where
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Subshell    ( )         Yes               Anywhere on the line
Code block  { }         No                After newline, semicolon, or keyword


----------------
Test Expressions
for use with test(1), and [ , as builtin and utility.
(By the way, did you know that '/bin/[' exists as a binary?)

string         string is not null
-b file        file is a block device file.
-c file        file is a character device file.
-d file        file is a directory.
-e file        file exists.
-f file        file is a regular file.
-g file        file has its setgid bit set.
-h file        file is a symbolic link.
-L file        file is a symbolic link. (Same as –h.)
-n string      string is non-null.
-p file        file is a named pipe (FIFO file).
-r file        file is readable.
-S file        file is a socket.
-s file        file is not empty.
-tn            File descriptor n points to a terminal.
-u file        file has its setuid bit set.
-w file        file is writable.
-x file        file is executable, or file is a directory that can be searched.
-z string      string is null.
s1=s2          Strings s1 and s2 are the same.
s1!=s2         Strings s1 and s2 are not the same.
n1 -eq n2      Integers n1 and n2 are equal.
n1 -ne n2      Integers n1 and n2 are not equal.
n1 -lt n2      n1 is less than n2.
n1 -gt n2      n1 is greater than n2.
n1 -le n2      n1 is less than or equal to n2.
n1 -ge n2      n1 is greater than or equal to n2.

-a             Logical and operator
n1 -gt n2 -a n1 -gt n3
-o             Logical or operator
n1 -gt n2 -o n1 -gt n3

---------------------
echo Escape Sequences

WARNING: echo escape behavior is NOT portable across shells.
DASH processes escapes by default; FreeBSD sh requires -e.
Use printf for any output that matters.  See OPEN PROBLEMS
in shell_training.txt for full details.

\a      Alert character, usually the ASCII BEL character.
\b      Backspace.
\c      Suppress the final newline in the output. Furthermore, any characters
        left in the argument, and any following arguments, are ignored (not
        printed).
\f      Formfeed.
\n      Newline.
\r      Carriage return.
\t      Horizontal tab.
\v      Vertical tab.
\\      A literal backslash character.
\0ddd   Character represented as a 1- to 3-digit octal value.


-----------------------
printf Escape Sequences

\a      Alert character, usually the ASCII BEL character.
\b      Backspace.
\c      Suppress any final newline in the output.a Furthermore, any characters
        left in the argument, any follow- ing arguments, and any characters left
        in the format string are ignored (not printed).
\f      Formfeed.
\n      Newline.
\r      Carriage return.
\t      Horizontal tab.
\v      Vertical tab.
\\      A literal backslash character.
\ddd    Character represented as a 1- to 3-digit octal value. Valid only in the
        format string. \0ddd Character represented as a 1- to 3-digit octal
        value.

--------------------------------
POSIX BRE and ERE metacharacters

\      BRE/ERE      Usually, turn off the special meaning of the following
                    character. Occasionally, enable a special meaning for the
                    following character, such as for \(...\) and \{...\}.
.      BRE/ERE      Match any single character except NUL. Individual programs
                    may also disallow match- ing newline.
*      BRE/ERE      Match any number (or none) of the single character that
                    immediately precedes it. For EREs, the preceding character
                    can instead be a regular expression. For example, since .
                    (dot) means any character, .* means “match any number of any
                    character.” For BREs, * is not special if it’s the first
                    character of a regular expression.
^      BRE/ERE      Match the following regular expression at the beginning of
                    the line or string. BRE: spe- cial only at the beginning of
                    a regular expression. ERE: special everywhere.
$      BRE/ERE      Match the preceding regular expression at the end of the
                    line or string. BRE: special only at the end of a regular
                    expression. ERE: special everywhere.
[...]  BRE/ERE      Termed a bracket expression, this matches any one of the 
                    enclosed characters. A hyphen (-) indicates a range of
                    consecutive characters. (Caution: ranges are locale-
                    sensitive, and thus not portable.) A circumflex (^) as the
                    first character in the brackets reverses the sense: it
                    matches any one character not in the list. A hyphen or close
                    bracket (]) as the first character is treated as a member of
                    the list. All other metacharac- ters are treated as members
                    of the list (i.e., literally). Bracket expressions may
                    contain collating symbols, equivalence classes, and
                character classes (described shortly).
\{n,m\} BRE     Termed an interval expression, this matches a range of
                occurrences of the single character that immediately
                precedes it. \{n\} matches exactly n occurrences, \{n,\ }
                matches at least n occurrences, and \{n,m\} matches any
                number of occurrences between n and m. n and m must be
                between 0 and RE_DUP_MAX (minimum value: 255), inclusive.
\( \)   BRE     Save the pattern enclosed between \( and \) in a special
                holding space. Up to nine subpatterns can be saved on a
                single pattern. The text matched by the subpat- terns can be
                reused later in the same pattern, by the escape sequences 
                \1 to \9. For example, \(ab\).*\1 matches two occurrences of
                ab, with any number of characters in between.
\n      BRE     Replay the nth subpattern enclosed in \( and \) into the
                pattern at this point. n is a number from 1 to 9, with 1
                starting on the left.
{n,m}   ERE     Just like the BRE \{n,m\} earlier, but without the
                backslashes in front of the braces.
+       ERE     Match one or more instances of the preceding regular expression.
?       ERE     Match zero or one instances of the preceding regular expression.
|       ERE     Match the regular expression specified before or after.
()      ERE     Apply a match to the enclosed group of regular expressions.

Note: \d, \w, \s, \b are PCRE/Perl extensions, not BRE or ERE.
      Portable equivalents: [[:digit:]], [_[:alnum:]], [[:space:]].
      There is no portable equivalent for \b; use grep -w.

-------------------------------------------
Simple regular expression matching examples

scully    The six letters scully, anywhere on a line
^scully   The six letters scully, at the beginning of a line
scully$   The six letters scully, at the end of a line
^scully$  A line containing exactly the six letters scully, and nothing else
[Ss]cully Either the six letters Scully, or the six letters scully, anywhere
          on a line
scu.ly    three letters scu, any character, and the two letters ly, anywhere
          on a line
scu.*ly   The three letters scu, any sequence of zero or more characters, and
          the two letters ly, anywhere on a line (e.g., scuyly, scully,
          scuWHOlly, and so on)


-----------------------
POSIX character classes

[:alnum:]      Alphanumeric characters
[:alpha:]      Alphabetic characters
[:blank:]      Space and tab characters
[:cntrl:]      Control characters
[:digit:]      Numeric characters
[:graph:]      Nonspace characters
[:lower:]      Lowercase characters
[:print:]      Printable characters
[:punct:]      Punctuation characters
[:space:]      Whitespace characters
[:upper:]      Uppercase characters
[:xdigit:]     Hexadecimal digit characters (0-9, a-f, A-F)


------------------------
printf Format Specifiers

%b    The corresponding argument is treated as a string containing escape
%c    ASCII character. Print the first character of the corresponding argument.
%d, %i    Decimal integer.
%e    Floating-point format ([-]d.precisione[+-]dd).
%E    Floating-point format ([-]d.precisionE[+-]dd).
%f    Floating-point format ([-]ddd.precision).
%g    %e or %f conversion, whichever is shorter, with trailing zeros removed.
%G    %E or %f conversion, whichever is shorter, with trailing zeros removed.
%o    Unsigned octal value.
%s    String.
%u    Unsigned decimal value.
%x    Unsigned hexadecimal number. Use a–f for 10 to 15.
%X    Unsigned hexadecimal number. Use A–F for 10 to 15.
%%    Literal %.


--------------------
Meaning of precision

%d, %i, %o, %u, %x, %X
         The minimum number of digits to print. When the value has fewer digits,
         it is padded with leading zeros. The default precision is 1.
%e, %E   The minimum number of digits to print. When the value has fewer digits,
         it is padded with zeros after the decimal point. The default precision
         is 6. A precision of 0 inhibits printing of the decimal point.
%f       The number of digits to the right of the decimal point.
%g, %G   The maximum number of significant digits.
%s       The maximum number of characters to print.


----------------
Flags for printf

–      Left-justify the formatted value within the field.
+      Always prefix numeric values with a sign, even if the value is positive.
#      Use an alternate form: %o has a preceding 0; %x and %X are prefixed with
       0x and 0X, respectively; %e, %E, and %f always have a decimal point in
       the result; and %g and %G do not have trailing zeros removed.
0      Pad output with zeros, not spaces. This happens only when the field width
       is wider than the converted result. In the C language, this flag applies
       to all output formats, even nonnumeric ones. For the printf command, it
       applies only to the numeric formats.

----------------------------------------------
Glob patterns (shell wildcards and case labels)

These are glob patterns (fnmatch), NOT regular expressions.
Used by: filename expansion, case labels, ${var#pattern},
         ${var%pattern}, find -name.

?       Any single character
*       Any string of characters
[set]   Any character in set
[!set]  Any character not in set

  case "${input}" in
    start*|begin*)  handle_start ;;
    *.tar.gz)       handle_tarball ;;
    [Yy]|[Yy]es)   confirm ;;
    *)              default ;;
  esac

Note: | in case separates patterns (OR).  It is NOT regex
      alternation.  There is no +, no {n,m}, no grouping.
      Glob is simpler than regex.  That is the point.


---------------------------------
Using the set construct wildcards

[abc]          a, b, or c
[.,;]          Period, comma, or semicolon
[-_]           Dash or underscore
[a-c]          a, b, or c
[a-z]          Any lowercase letter
[!0-9]         Any nondigit
[0-9!]         Any digit, or an exclamation mark
[a-zA-Z]       Any lower- or uppercase letter
[a-zA-Z0-9_-]  Any letter, any digit, underscore, or dash


---------
expr operators

e1|e2    If e1 is nonzero or non-null, its value is used. Otherwise, if e2 is
         nonzero or non-null, its value is used. Otherwise, the final value is
         zero.
e1&e2    If e1 and e2 are non-zero or non-null, the return value is that of e1.
         Otherwise, the final value is zero.

e1=e2    Equal.
e1!=e2   Not equal.
e1<e2    Less than.
e1<=e2   Less than or equal to.
e1>e2    Greater than.
e1>=e2   Greater than or equal to.
         These operators cause expr to print 1 if the indicated comparison is
         true, 0 otherwise. If both oper- ands are integers, the comparison is
         numeric; otherwise, it’s a string comparison.

e1+e2    The sum of e1 and e2.
e1-e2    The difference of e1 and e2.
e1*e2    The product of e1 and e2.
e1/e2    The integer division of e1 by e2 (truncates).
e1%e2    The remainder of the integer division of e1 by e2 (truncates).
e1:e2    Match of e1 to BRE e2; see the expr(1) manpage for details.
( expression )  The value of expression; used for grouping, as in most
                programming languages.
integer    A number consisting only of digits, although an optional leading 
           minus sign is allowed. Sadly, unary plus is not supported.
string    A string value that cannot be mistaken for a number or an operator.


--------------------
arithmetic operators

++ --
        Left to Right  Increment and decrement, prefix and postfix
+-!~
        Right to Left  Unary plus and minus; logical and bitwise negation
* /%
        Left to Right  Multiplication, division, and remainder
+-
        Left to Right  Addition and subtraction
<< >>
        Left to Right  Bit-shift left and right
< <= > >=
        Left to Right  Comparisons
= = !=
        Left to Right  Equal and not equal
&
        Left to Right  Bitwise AND
^
        Left to Right  Bitwise Exclusive OR
|
        Left to Right  Bitwise OR
&&
        Left to Right  Logical AND (short-circuit)
||
        Left to Right  Logical OR (short-circuit)
?:
        Right to Left  Conditional expression
= += -= *= /= %= &= ^= <<= >>= |=
        Right to Left  Assignment operators

--------------------
Sort key field types

b      Ignore leading whitespace.
d      Dictionary order.
f      Fold letters implicitly to a common lettercase.
g      Compare as general floating-point numbers. GNU origin; present on most modern systems. Not base POSIX.
i      Ignore nonprintable characters.
n      Compare as (integer) numbers.
r      Reverse the sort order.


---------------------
Shell options for set
(be warned, set is the interface for misfit features in all shells)

-a   allexport      POSIX         Export all subsequently defined variables.
-b   notify         POSIX         Print job completion messages right away, instead of waiting for next prompt. Intended for interactive use.
-B   braceexpand    bash          Enable brace expansion. On by default. See “Brace Expansion” [14.3.4] for more information.
-C   noclobber      POSIX         Don’t allow > redirection to existing files. The >| oper- ator overrides the setting of this option. Intended for interactive use.
-e   errexit        POSIX         Exit the shell when a command exits with nonzero status.
-f   noglob         POSIX         Disable wildcard expansion.
-m   monitor        POSIX         Enable job control (on by default). Intended for inter- active use.
-n   noexec         POSIX         Read commands and check for syntax errors, but don’t execute them. Interactive shells are allowed to ignore this option.
-u   nounset        POSIX         Treat undefined variables as errors, not as null.
-v   verbose        POSIX         Print commands (verbatim) before running them.
-x   xtrace         POSIX         Print commands (after expansions) before running them.
     ignoreeof      POSIX         Disallow Ctrl-D to exit the shell.
     nolog          POSIX         Disable command history for function definitions.
     vi             POSIX         Use vi-style command-line editing. Intended for interactive use.

-A   ksh88,ksh93  Array assignment. set +A does not clear the array. Refer to Korn shell “Indexed Arrays”for more information.
-H   trackall (ksh)             Same as POSIX -f noglob, Disable wildcard expansion.
-s   ksh88, ksh93    Sort the positional parameters.


Common shell options which, for portability, should be avoided:

-h   hashall (bash) POSIX  Locate and remember the location of commands called from function bodies when the function is defined, instead of when the function is executed (XSI).
-k   histexpand  bash            Enable !-style history expansion. On by default.
-P   physical    bash            Use the physical directory structure for commands that change directory.
     history     bash            Enable command history. On by default.
     posix       bash            Enable full POSIX compliance.
     markdirs    ksh88, ksh93    Append a / to directories when doing wildcard expansion.
     pipefail    ksh93           Make pipeline exit status be that of the last command that fails, or zero if all OK. ksh93n or newer.
     viraw       ksh88, ksh93    Use vi-style command-line editing. Intended for interactive use. This mode can be slightly more CPU- intensive than set -o vi.
-p   privileged  bash, ksh88,    ksh93    Attempt to function in a more secure mode. The details differ among the shells; see your shell’s docu- mentation.
-t   bash,       ksh88, ksh93    Read and execute one command and then exit. This is obsolete; it is for compatibility with the Bourne shell and should not be used.
     bgnice      ksh88, ksh93    Automatically lower the priority of all commands run in the background (with &).
     emacs       bash, ksh88,    ksh93    Use emacs-style command-line editing. Intended for interactive use.
     gmacs       ksh88, ksh93    Use GNU emacs-style command-line editing. Intended for interactive use.



---------------------------------------------------------
POSIX shell built-in commands, a real-world portable list
(If utility exists, built-in will be run unless utility is explicitly called)

: (colon)      Do nothing (just do expansions of arguments).
. (dot)        Read file and execute its contents in current shell,
               (to 'source' a file in bash).
alias          Set up shorthand for command or command line (interactive use).
bg             Put a job in background (interactive use).
break          Exit from surrounding for, while, or until loop.
cd             Change working directory
command        Locate built-in and external commands; find a built-in command instead of an identically named function.
continue       Skip to next iteration of for, while, or until loop.
eval           Process arguments as a command line.
exec           Replace shell with given program or change I/O for shell.
exit           Exit from shell.
export         Create environment variables.
false          Do nothing, unsuccessfully.
fc             Work with command history (interactive use).
fg             Put background job in foreground (interactive use).
getopts        Process command-line options, (also less portable getopt).
hash           Manage command location hash table.  See HASH below.
jobs           List
kill           Send signals.
newgrp         Start new shell with new group ID (obsolete).
pwd            Print working directory.
read           Read a line from standard input.
readonly       Make variables read-only (unassignable).
return         Return from surrounding function.
set            Set options or positional parameters.
shift          Shift command-line arguments.
times          Print accumulated user and system CPU times for the shell and its children.
trap           Set up signal-catching routine.
true           Do nothing, successfully.
umask          Set/show file permission mask.
unalias        Remove alias definitions (interactive use).
unset          Remove definitions of variables or functions.
wait           Wait for background job(s) to finish.


----------------------------------------------
Common utilities — portability notes

These are utilities used so frequently that their portability traps
should be known without running mancheck every time. This is not a
catalogue of all utilities — use mancheck for anything not listed here.

sleep NUMBER
       POSIX specifies integer seconds only. Fractional seconds
       (sleep 0.5, sleep 0.2) are a non-portable extension, first
       introduced in GNU sh-utils 2.0a (2002). Supported on:

       FreeBSD       since at least 5.0 (2003)
       OpenBSD       documented in examples as of 7.8
       GNU/Linux     GNU coreutils, since 2002
       macOS         BSD-derived, supports fractions

       Not available: V7 AT&T UNIX, 4.4BSD Lite2, FreeBSD 2.0,
       and any strict POSIX-only implementation.

       Use leading zero: sleep 0.2, not sleep .2 — some
       implementations may reject bare decimal point.

       Unit suffixes (s, m, h, d) and multiple arguments that
       are summed together are GNU/FreeBSD extensions, not POSIX.


------------------------------------
PIPE_BUF — atomic write size to pipes

When two processes write to the same pipe at the same time,
writes of PIPE_BUF bytes or fewer are guaranteed atomic — the
data arrives as one contiguous chunk, never interleaved with
another writer's data.  Writes larger than PIPE_BUF may be
interleaved.

PIPE_BUF varies across systems:

  POSIX minimum:   512 bytes
  FreeBSD:         512
  macOS:           512
  Linux:          4096
  Solaris:        5120

A 1000-byte write is atomic on Linux (1000 < 4096) but NOT
atomic on FreeBSD (1000 > 512).  Same code, different behavior.
No error, no warning — the data just scrambles.

The safe floor: keep pipe writes <= 512 bytes, or accept that
atomicity is not guaranteed on all platforms.


----------------------------------------------
Process substitution — portability warning

Process substitution <(cmd) and >(cmd) is NOT portable.
Available in bash, ksh93, zsh.  Absent from dash (Ubuntu
/bin/sh), ash, and Bourne-lineage sh.

Do not use in #!/bin/sh programs.  Alternatives:
  - Named pipes: mkfifo, then read/write the fifo
  - Temp files: cmd > tmpfile, then read tmpfile
  - Pipe restructuring: rearrange the pipeline

If used, call it out explicitly with a comment.


----------------------------------------------
trap — signal handling and cleanup

trap 'commands' SIGNAL [SIGNAL ...]
trap '' SIGNAL              # ignore signal
trap - SIGNAL               # reset to default
trap                        # list current traps (no args)

Use signal NAMES, not numbers.  Names are portable.
Numbers diverge above signal 15 (see Signal Names table).

  trap 'rm -f "${tmpfile}"' EXIT        # cleanup on any exit
  trap 'echo "interrupted" >&2' INT     # handle Ctrl-C
  trap '' HUP                           # ignore hangup (nohup)

EXIT (signal 0) fires on any exit — normal, die(), signal death.
It always runs last.  This is the most useful trap.

ORDER MATTERS: set the trap BEFORE creating the resource it
cleans up.  If a signal arrives between creation and trap
registration, the resource is orphaned.

  trap 'rm -f "${tmpfile}"' EXIT        # FIRST: register cleanup
  tmpfile="/tmp/${0##*/}.$$"            # THEN: create the file

Bourne, 1978: "The trap command appears before the creation of
the temporary file; otherwise it would be possible for the
process to die without removing the file."


----------------------------------------------
Portable Filesystem Paths — quick reference

Verified across FreeBSD, OpenBSD, Linux.  For shell programs.

  Path/Device       Port?   Man page     Notes
  ---------------   -----   ----------   ---------------------------
  /dev/null         yes     null(4)      Discard output, empty input
  /dev/zero         yes     zero(4)      Endless \0 stream for dd
  /dev/tty          yes     tty(4)       Controlling terminal
  /dev/stdin        yes     fd(4)        = /dev/fd/0
  /dev/stdout       yes     fd(4)        = /dev/fd/1
  /dev/stderr       yes     fd(4)        = /dev/fd/2
  /dev/fd/N         mostly  fd(4)        FB needs fdescfs for N>2
  /dev/urandom      yes     random(4)    Non-blocking random bytes
  /dev/random       NO      random(4)    Blocks on old Linux; use urandom
  /tmp              yes     hier(7)      1777, use mktemp, honor $TMPDIR
  /var/tmp          mostly  hier(7)      OB: may = /tmp
  /var/run          yes     hier(7)      LX: often symlink to /run
  FIFO (mkfifo)     yes     mkfifo(1)    Blocks until both ends open

Traps:

1. /dev/random is NOT portable.  Use /dev/urandom.  Always.

2. /dev/fd/N for N>2 requires fdescfs on FreeBSD.

3. $TMPDIR overrides /tmp.  Portable temp file creation:
     mktemp "${TMPDIR:-/tmp}/prog.XXXXXXXX"

4. /var/tmp is NOT guaranteed to survive reboot on all systems.
   OpenBSD may symlink it to /tmp.

5. FIFOs block on open.  The shell has no O_NONBLOCK.  Design
   your producer/consumer startup order accordingly.

6. /var/run vs /run: on modern Linux, /var/run -> /run.  Both
   paths work.  Use /var/run for portability.

7. /dev/console is root-only.  If you need "the terminal," you
   want /dev/tty, not /dev/console.

8. /dev/stdin on setuid programs: OpenBSD returns EPERM.  This
   is a security feature, not a bug.


HASH — COMMAND LOCATION CACHE
================================

The shell maintains a hash table of command locations so it
does not search PATH on every invocation.  hash(1) is a POSIX
required regular built-in (IEEE Std 1003.1-2017).

Added to the Bourne shell between the 1982 and 1987 editions
(System V).  Documented by Bourne with one line in the
built-in commands table.  Nearly forgotten since — the builtin
that fell through the crack between the end of Bell Labs and
the start of internet documentation.

PORTABLE SUBSET (verified across 7 implementations + POSIX):

  hash              Print the hash table contents.
                    NOTE: output format is UNSPECIFIED by
                    POSIX.  Every shell prints differently.
                    Do not parse this output.

  hash cmd          Look up cmd in PATH and cache the result.
                    Next invocation of cmd skips PATH search.
                    If cmd is not found, the shell reports
                    an error.

  hash -r           Forget everything.  Clear the entire hash
                    table.  The shell will re-search PATH for
                    every command on next invocation.

WHEN TO USE hash -r:

  After installing new software:
    # make install
    # hash -r
  Without hash -r, the shell may still find the OLD
  binary at the OLD location.  The hash table cached it.
  This is the #1 reason practitioners think "I installed
  it but the shell can't find it."  hash -r fixes it.

  After modifying PATH:
    PATH="/new/path:${PATH}"
    hash -r
  Some shells (bash) auto-clear on PATH assignment.
  Most do not.  hash -r is the portable guarantee.

  In programs that modify the environment:
    If your program installs, moves, or removes other
    programs, follow with hash -r.  The next command
    lookup will be fresh.

EXISTENCE TEST (portable, lightweight):

  hash cmd 2>/dev/null
    Returns 0 if cmd is in PATH, non-zero if not.
    Lighter than command -v: skips aliases, functions,
    and builtins.  Tests ONLY whether cmd exists as an
    external command in PATH.

    if hash curl 2>/dev/null; then
      # curl is available
    fi

  Compare:
    command -v cmd    finds aliases, functions, builtins,
                      AND external commands
    hash cmd          finds ONLY external commands in PATH
    which cmd         NOT portable (not in POSIX, behavior
                      varies wildly)
    type cmd          output format not portable

PORTABILITY MATRIX:

  Operation        POSIX  FreeBSD  OpenBSD  NetBSD  macOS  dash  bash
  ─────────────────────────────────────────────────────────────────────
  hash             yes    yes      yes      yes     yes    yes   yes
  hash cmd         yes    yes      yes      yes     yes    yes   yes
  hash -r          yes    yes      yes      yes     yes    yes   yes
  hash -v          no     yes      no       yes     yes    no    no
  hash -d cmd      no     no       no       no      no     no    yes
  hash -p path     no     no       no       no      no     no    yes
  hash -t cmd      no     no       no       no      no     no    yes
  hash -l          no     no       no       no      no     no    yes

  Use ONLY: hash, hash cmd, hash -r.
  Everything else is implementation-specific.

DOES NOT SURVIVE SUBSHELLS:

  The hash table is per-process.  A subshell inherits a
  copy (fork semantics).  Changes in the subshell do not
  propagate to the parent.

    hash -r          # clears parent's table
    (hash -r)        # clears subshell's copy only
    # parent's table is unchanged

  Same as variables.  Same as everything in UNIX.

INTERACTION WITH OTHER BUILTINS:

  command -v cmd    may consult the hash table, but also
                    checks aliases, functions, builtins
  type cmd          typically shows "cmd is hashed (/path)"
                    when the command is in the hash table
  exec cmd          bypasses the hash table entirely
                    (exec always searches PATH fresh)

WHAT hash IS NOT:

  hash is not set -h (hashall).  set -h is a set flag that
  controls WHEN hashing happens (at function definition vs
  function execution).  hash is the builtin that manages
  the table directly.  They are related but distinct.

  The shelltables entry for set -h (line 732) correctly
  lists it as "avoid for portability."  The hash BUILTIN
  is portable.  The set -h FLAG is not.

Source: mancheck hash modern (2026-04-18).
Cross-platform verification: examples/hash_*.txt (8 files).
