# 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 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 Returns the path to the utility if it exists, heritage from C shell. command -v Returns the path to the utility, -v flag keeps it silent, -V is default behavior. Very portable. whereis 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. e1e2 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).