diff --git a/docs/commands/builtin/caller.md b/docs/commands/builtin/caller.md new file mode 100644 index 0000000..188ed25 --- /dev/null +++ b/docs/commands/builtin/caller.md @@ -0,0 +1,82 @@ +# The caller builtin command + +## Synopsis + + caller [FRAMENUMBER] + +## Description + +The `caller` builtin command is used to print execution frames of +subroutine calls. Without giving a framenumber, the topmost execution +frame information is printed (\"who called me\") wile linenumber and +filename. + +When an execution frame number is given (0 - topmost), the linenumber, +the subroutine (function) and the filename is printed. When an invalid +execution frame number is given, it exists `FALSE`. This way it can be +used in a loop (see the examples section below). + +## Examples + +### Simple stack trace + +The code below defines a function `die` that is used to exit the +program. It prints a list of execution frames, starting with the topmost +frame (0). The topmost frame is the \"caller of the die function\", in +this case function \"f1\". + +This way, you can print a \"stack trace\" for debugging or logging +purposes. + +The code is made very simple, just to show the basic purposes. + +``` bash +#!/bin/bash + +die() { + local frame=0 + while caller $frame; do + ((++frame)); + done + echo "$*" + exit 1 +} + +f1() { die "*** an error occured ***"; } +f2() { f1; } +f3() { f2; } + +f3 +``` + +**Output** + + 12 f1 ./callertest.sh + 13 f2 ./callertest.sh + 14 f3 ./callertest.sh + 16 main ./callertest.sh + *** an error occured *** + +## Notes + +- `caller` produces no output unless used within a script that\'s run + from a real file. It isn\'t particularly useful for interactive use, + but can be used to create a decent `die` function to track down + errors in moderately complex scripts. + `{ bash /dev/stdin; } <<<$'f(){ g; }\ng(){ h; }\nh(){ while caller $((n++)); do :; done; }\nf'` +- For more sophisticated debugging, Bash extended debugging features + are available and a number of special parameters that give more + detail than caller (e.g. BASH_ARG{C,V}). Tools such as + [Bashdb](http://bashdb.sourceforge.net/) can assist in using some of + Bash\'s more advanced debug features. +- The Bash manpage and help text specifies that the argument to + `caller` is an \"expr\" (whatever that means). Only an integer is + actually allowed, with no special interpretation of an + \"expression\" as far as we can tell. + +## Portability considerations + +- `caller` is not specified by POSIX(R) +- the `caller` builtin command appeared in Bash version 3.0 + +## See also diff --git a/docs/commands/builtin/cd.md b/docs/commands/builtin/cd.md new file mode 100644 index 0000000..e085381 --- /dev/null +++ b/docs/commands/builtin/cd.md @@ -0,0 +1,59 @@ +# The cd builtin command + +## Synopsis + + cd [-L|-P] [DIRECTORY] + + cd - + +## Description + +The `cd` builtin command is used to change the current working directory + +- to the given directory (`cd DIRECTORY`) +- to the previous working directory (`cd -`) as saved in the + [OLDPWD](/syntax/shellvars#OLDPWD) shell variable +- to the user\'s home directory as specified in the + [HOME](/syntax/shellvars#HOME) environment variable (when used + without a `DIRECTORY` argument) + +The `cd` builtin command searches the directories listed in +[CDPATH](/syntax/shellvars#CDPATH) for a matching directory. + +The default behaviour is to follow symbolic links unless the `-P` option +is given or the shell is configured to do so (see the `-P` option of +[the set builtin command](/commands/builtin/set)). + +### Options + + Option Description + -------- ---------------------------------------------------- + `-L` Follow symbolic links (default) + `-P` Do not follow symbolic links + `-@` Browse a file\'s extended attributed, if supported + +### Exit status + +- true if the directory was changed successfully +- false if a change to the home directory was requested, but + [HOME](/syntax/shellvars#HOME) is unset +- false if anything else goes wrong + +## Examples + +### Change the working directory to the user\'s home directory + + cd + +### Change the working directory to the previous directory + + cd - + +## Portability considerations + +## See also + +- variable [CDPATH](/syntax/shellvars#CDPATH) +- variable [HOME](/syntax/shellvars#HOME) +- variable [OLDPWD](/syntax/shellvars#OLDPWD) +- the `-P` option of [the set builtin command](/commands/builtin/set) diff --git a/docs/commands/builtin/declare.md b/docs/commands/builtin/declare.md new file mode 100644 index 0000000..b67b5cc --- /dev/null +++ b/docs/commands/builtin/declare.md @@ -0,0 +1,184 @@ +# The declare builtin command + +## Synopsis + + declare [-aAfFgilnrtux] [-p] [NAME[=VALUE] ...] + + # obsolete typeset synonym + typeset [-aAfFgilnrtux] [-p] [NAME[=VALUE] ...] + +## Description + +`declare` is used to display or set variables along with variable +attributes. When used to display variables/functions and their value, +the output is re-usable as input for the shell. + +If no `NAME` is given, it displays the values of all variables or +functions when restricted by the `-f` option. + +If `NAME` is followed by `=VALUE`, `declare` also sets the value for a +variable. + +When used in a function, `declare` makes `NAMEs` local variables, unless +used with the `-g` option. + +Don\'t use it\'s synonym `typeset` when coding for Bash, since it\'s +tagged as obsolete. + +### Options + +Below, `[-+]X` indicates an attribute, use `-X` to set the attribute, +`+X` to remove it. + + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Option Description + --------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------ + `[-+]a` make NAMEs indexed arrays (removing with `+a` is valid syntax, but leads to an error message) + + `[-+]A` make NAMEs associative arrays + + `[-+]c` **Undocumented** convert NAMEs to \"capcase\" on assignment (makes the first letter upper-case and the rest lower). Requires Bash built with `-DCASEMOD_CAPCASE` + + `-f` restrict action or display to function names and definitions (removing with `+f` is valid syntax, but leads to an error message) + + `-F` restrict display to function names only (plus line number and source file when debugging) + + `-g` create global variables when used in a shell function; otherwise ignored (by default, `declare` declares local scope variables when used in shell functions) + + `[-+]i` make NAMEs have the \"integer\" attribute + + `[-+]l` convert NAMEs to lower case on assignment (makes sure the variable contains only lower case letters) + + `[-+]n` make NAME a reference to the variable named by its value. Introduced in Bash 4.3-alpha.\ + \'\' \${!NAME}\'\' reveals the reference variable name, VALUE.\ + Use `unset -n NAME` to unset the variable. (`unset -v NAME` unsets the VALUE variable.)\ + Use `[[ -R NAME ]]` to test if NAME has been set to a VALUE, another variable\'s name. + + `-p` display the attributes and value of each NAME + + `[-+]r` make NAMEs readonly (removing with `+r` is valid syntax, but not possible) + + `[-+]t` make NAMEs have the \"trace\" attribute (effective only for functions) + + `[-+]u` convert NAMEs to upper case on assignment (makes sure the variable contains only upper case letters) + + `[-+]x` make NAMEs exported + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +### Return status + + Status Reason + -------- ---------------------------------------------------------------------------------------- + 0 no error + != 0 invalid option + != 0 invalid variable name given + != 0 attempt to **define** a function using `-f` + != 0 assignment to a readonly variable + != 0 removing the readonly-attribute from a readonly variable + != 0 assignment to an array variable without the compound assignment syntax (`array=(...)`) + != 0 attempt to use `+a` to \"destroy\" an array + != 0 attemt to display a non-existent function with `-f` + +## Notes + +Unix shells offer very few datatypes. Bash and some other shells extend +this by allowing \"attributes\" to be set on variable names. The only +attributes specified by POSIX are `export` and `readonly`, which are set +by their own dedicated builtins. Datatypes in bash have a few other +interesting capabilities such as the ability to modify data on +assignment. + +## Examples + +### Display defined functions + +`declare -f` can be used to display all defined functions\... + + $ declare -f + foo () + { + echo "FOO is BAR" + } + world () + { + echo "Hello World!" + } + +\...or just a specific defined function. + + $ declare -f foo + foo () + { + echo "FOO is BAR" + } + +### Nameref + +Bash 4.3 adds a new way to indirectly reference variables. `typeset -n` +or `declare -n` can be used to make a variable indirectly refer to +another. In Bash, the lvalue of the assignment given to `typeset -n` or +`declare -n` will refer to the variable whose name is expanded on the +RHS. + +`typeset -n` is used in the example below. See notes below. + + # Sum a set of arrays and assign the result indirectly, also printing each intermediary result (without portability workarounds) + # sum name arrname [ arrname ... ] + function sum { + typeset -n _result=$1 _arr + typeset IFS=+ + _result=0 + for _arr in "${@:2}"; do # Demonstrate the special property of "for" on a nameref. + (( _result += ${_arr[*]} )) + printf '%s = %d\n' "${!_result}" "$_result" # Demonstrate the special property of ${!ref} on a nameref. + done + } + + a=(1 2 3) b=(6 5 4) c=(2 4 6) + sum total a b c + printf 'Final value of "total" is: %d\n' "$total" + +\
function sum { + + typeset -n _result=$1 + shift + typeset IFS=+ _arrx + _result=0 + for _arrx in "$@"; do # Demonstrate the special property of "for" on a nameref. + typeset -n _arr=$_arrx + (( _result += ${_arr[*]} )) + printf '%s = %d\n' "${!_result}" "$_result" # Demonstrate the special property of ${!ref} on a nameref. + done + +} + +a=(1 2 3); b=(6 5 4); c=(2 4 6) sum total a b c printf \'Final value of +\"total\" is: %d\\n\' \"\$total\" \ + +`typeset -n` is currently implemented in ksh93, mksh, and Bash 4.3. Bash +and mksh\'s implementations are quite similar, but much different from +ksh93\'s. See [Portability considerations](#portability_considerations) +for details. ksh93 namerefs are much more powerful than Bash\'s. + +## Portability considerations + +- `declare` is not specified by POSIX(r) +- `declare` is unique to Bash and totally non-portable with the + possible exception of Zsh in Bash compatibility mode. Bash marks the + synonym `typeset` as obsolete, which in Bash behaves identically to + `declare`. All other Korn-like shells use `typeset`, so it probably + isn\'t going away any time soon. Unfortunately, being a non-standard + builtin, `typeset` differs significantly between shells. ksh93 also + considers `typeset` a special builtin, while Bash does not - even in + POSIX mode. If you use `typeset`, you should attempt to only use it + in portable ways. +- **todo** nameref portability\... + +## See also + +- [arrays](/syntax/arrays) +- [readonly](/commands/builtin/readonly) +- [unset](/commands/builtin/unset) +- [declaration commands](http://austingroupbugs.net/view.php?id=351) + will change the behavior of certain builtins such as `export` in the + next version of POSIX. diff --git a/docs/commands/builtin/echo.md b/docs/commands/builtin/echo.md new file mode 100644 index 0000000..4f3027a --- /dev/null +++ b/docs/commands/builtin/echo.md @@ -0,0 +1,92 @@ +# The echo builtin command + +## Synopsis + + echo [-neE] [arg ...] + +## Description + +`echo` outputs it\'s args to stdout, separated by spaces, followed by a +newline. The return status is always `0`. If the +[shopt](/commands/builtin/shopt) option `xpg_echo` is set, Bash +dynamically determines whether echo should expand escape characters +(listed below) by default based on the current platform. `echo` doesn\'t +interpret `--` as the end of options, and will simply print this string +if given. + +### Options + + Option Description + -------- ---------------------------------------------------------------------------------------------------------------- + `-n` The trailing newline is suppressed. + `-e` Interpretation of the following backslash-escaped characters (below) is enabled. + `-E` Disables the interpretation of these escape characters, even on systems where they are interpreted by default. + +### Escape sequences + + Escape Description + -------------- --------------------------------------------------------------------------------------------------------------- + `\a` alert (bell) + `\b` backspace + `\c` suppress further output + `\e` + `\E` an escape character + `\f` form feed + `\n` new line + `\r` carriage return + `\t` horizontal tab + `\v` vertical tab + `\\` backslash + `\0nnn` the eight-bit character whose value is the octal value nnn (zero to three octal digits) + `\xHH` the eight-bit character whose value is the hexadecimal value HH (one or two hex digits) + `\uHHHH` the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits) + `\UHHHHHHHH` the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits) + +## Examples + +## Portability considerations + +- `echo` is a portability train wreck. No major shell follows POSIX + completely, and any shell that attempts to do so should be + considered horribly broken. + [SUSv4](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37) + specifies that `echo` **shall not** include any options. Further, it + specifies that the behavior of `-n` as a first argument shall be + determined by the implementation, unless XSI is followed, in which + case `-n` is always treated as a string, and backslash escapes are + interpreted by default. `dash` has the misfeature of following this + and interpreting escapes by default, but includes a `-n` feature for + suppressing newlines nevertheless.\ + \ + In practice, if you\'re able to assume a korn-like shell including + bash, mksh, or zsh, `echo` when used in simple cases is generally + reliable. For example, in the very common situation in which echo is + supplied with a single argument and whose output is to have a + newline appended, using `echo` is considered common practice. + +```{=html} + +``` +- **Never use options to `echo`! *Ever*!** Any time you feel tempted + to use `echo -e`, `-n`, or any other special feature of echo, **use + [printf](/commands/builtin/printf) instead!** If portability is a + requirement, you should consider using `printf` *exclusively* and + just ignore that `echo` even exists. If you must use `echo -e` and + refuse to use `printf`, it is usually acceptable to use \'\'echo + \$\'\...\' \'\'if targeting only shells that support this special + quoting style. + +```{=html} + +``` +- `ksh93` has a `print` command, which if coding specifically for + `ksh93` should be preferred over `echo`. + [printf](/commands/builtin/printf) still includes most of the + functionality of both, and should usually be the most preferred + option. + +## See also + +- [printf](/commands/builtin/printf) +- +- diff --git a/docs/commands/builtin/eval.md b/docs/commands/builtin/eval.md new file mode 100644 index 0000000..de0bb0d --- /dev/null +++ b/docs/commands/builtin/eval.md @@ -0,0 +1,174 @@ +# The eval builtin command + +## Synopsis + + eval: eval [arg ...] + +## Description + +`eval` takes its arguments, concatenates them separated by spaces, and +executes the resulting string as Bash code in the current execution +environment. `eval` in Bash works in essentially the same way as most +other languages that have an `eval` function. Perhaps the easiest way to +think about `eval` is that it works in the same way as running \'\'bash +-c \"bash code\...\" \'\'from a script, except in the case of `eval`, +the given code is executed in the current shell environment rather than +a child process. + +## Examples + +In this example, the literal text within the +[here-document](/syntax/redirection#here_documents) is executed as Bash +code exactly as though it were to appear within the script in place of +the `eval` command below it. + + #!/usr/bin/env bash + { myCode=$( +``` +- `eval` is another one of the few Bash builtins with keyword-like + conditional parsing of arguments that are in the form of compound + assignments. + +```{=html} + +``` + $ ( eval a=( a b\\ c d ); printf '<%s> ' "${a[@]}"; echo ) # Only works in Bash. + + $ ( x=a; eval "$x"=( a b\\ c d ); printf '<%s> ' "${a[@]}"; echo ) # Argument is no longer in the form of a valid assignment, therefore ordinary parsing rules apply. + -bash: syntax error near unexpected token `(' + $ ( x=a; eval "$x"'=( a b\ c d )'; printf '<%s> ' "${a[@]}"; echo ) # Proper quoting then gives us the expected results. + + +We don\'t know why Bash does this. Since parentheses are metacharacters, +they must ordinary be quoted or escaped when used as arguments. The +first example above is the same error as the second in all non-Bash +shells, even those with compound assignment. + +In the case of `eval` it isn\'t recommended to use this behavior, +because unlike e.g. [declare](commands/builtin/declare), the initial +expansion is still subject to all expansions including +[word-splitting](syntax/expansion/wordsplit) and [pathname +expansion](syntax/expansion/glob). + + $ ( set -x; touch 'x+=(\[[123]\]=*)' 'x+=([3]=yo)'; eval x+=(*); echo "${x[@]}" ) + + touch 'x+=(\[[123]\]=*)' 'x+=([3]=yo)' + + eval 'x+=(\[[123]\]=*)' 'x+=([3]=yo)' + ++ x+=(\[[123]\]=*) + ++ x+=([3]=yo) + + echo '[[123]]=*' yo + [[123]]=* yo + +Other commands known to be affected by compound assignment arguments +include: [let](commands/builtin/let), +[declare](commands/builtin/declare), +[typeset](commands/builtin/typeset), [local](commands/builtin/local), +[export](commands/builtin/export), and +[readonly](commands/builtin/readonly). More oddities below show both +similarities and differences to commands like +[declare](commands/builtin/declare). The rules for `eval` appear +identical to those of [let](commands/builtin/let). + +## See also + +- [BashFAQ 48 - eval and security + issues](http://mywiki.wooledge.org/BashFAQ/048) \-- **IMPORTANT** +- [Another eval + article](http://fvue.nl/wiki/Bash:_Why_use_eval_with_variable_expansion%3F) +- [Indirection via + eval](http://mywiki.wooledge.org/BashFAQ/006#Assigning_indirect.2BAC8-reference_variables) +- [More indirection via + eval](http://fvue.nl/wiki/Bash:_Passing_variables_by_reference) +- [Martin Väth\'s \"push\"](https://github.com/vaeth/push) \-- + `printf %q` work-alike for POSIX. +- [The \"magic alias\" + hack](http://www.chiark.greenend.org.uk/~sgtatham/aliases.html) diff --git a/docs/commands/builtin/exec.md b/docs/commands/builtin/exec.md new file mode 100644 index 0000000..d3a85c2 --- /dev/null +++ b/docs/commands/builtin/exec.md @@ -0,0 +1,85 @@ +# The exec builtin command + +## Synopsis + + exec [-a NAME] [-cl] [COMMAND] [ARG...] [REDIRECTION...] + +## Description + +The `exec` builtin command is used to + +- **replace** the shell with a given program (executing it, **not as + new process**) +- set redirections for the program to execute or for the current shell + +If only redirections are given, the redirections affect the current +shell without executing any program. + +### Options + + Option Description + ----------- ---------------------------------------------------------------------------------------------------------------------- + `-a NAME` Passes `NAME` as zeroth argument for the program to be executed + `-c` Execute the program with an empty (cleared) environment + `-l` Prepends a dash (`-`) to the zeroth argument of the program to be executed, similar to what the `login` program does + +### Exit status + +- on redirection errors it returns 1, otherwise 0 +- on exec failures: + - a non-interactive shell terminates; if the [shell option + execfail](/internals/shell_options#execfail) is set `exec` + returns failure + - in an interactive shell, `exec` returns failure + +## Examples + +### Wrapper around a program + +``` bash +myprog=/bin/ls +echo "This is the wrapper script, it will exec $myprog" + +# do some vodoo here, probably change the arguments etc. +# well, stuff a wrapper is there for + +exec "$myprog" "$@" +``` + +### Open a file as input for the script + +``` bash +# open it +exec 3< input.txt + +# for example: read one line from the file(-descriptor) +read -u 3 LINE +# or +read LINE <&3 + +# finally, close it +exec 3<&- +``` + +### Overall script logfile + +To redirect the whole `stdout` and `stderr` of the shell or shellscript +to a file, you can use the `exec` builtin command: + +``` bash +exec >/var/adm/my.log 2>&1 + +# script continues here... +``` + +## Portability considerations + + *POSIX(r) specifies error code ranges: + * if ''exec'' can't find the program to execute, the error code shall be 126 + * on a redirection error, the error code shall be between 1 and 125 + * the ''-a NAME'' option appeared in Bash 4.2-alpha + * POSIX(r) does **not** specify any options for ''exec'' (like ''-c'', ''-l'', ''-a NAME''). + +## See also + +- [redirection](/syntax/redirection) diff --git a/docs/commands/builtin/exit.md b/docs/commands/builtin/exit.md new file mode 100644 index 0000000..35271bd --- /dev/null +++ b/docs/commands/builtin/exit.md @@ -0,0 +1,46 @@ +# The exit builtin command + +## Synopsis + + exit [N] + +## Description + +The `exit` command terminates the current shell (or script). + +If `N` is given, the return code to the parent process is set to `N`. If +not, the returned status the the status of the most recently executed +command (i.e. `$?`). + +A [trap](/commands/builtin/trap) on `EXIT` is executed before the shell +exits, except the executed `exit` command is part of an already running +trap. + +### Options + +There are no options. + +### Exit status + +Naturally, you can\'t ask for the exit status from within the shell that +executed the `exit` command, because the shell exits. + + Status Reason + -------- ---------------------------------------------------------------------------- + 255 invalid (e.g. non-numeric) argument - this staus is returned to the parent + +## Examples + +### Exit the shell and explicitely set its exit status + + exit 3 + +## Portability considerations + +- if `N` is specified, but its value is not between 0 and 255 + inclusively, the exit status is undefined. + +## See also + +- [The trap builtin command](/commands/builtin/trap) +- [The exit status](/dict/terms/exit_status) diff --git a/docs/commands/builtin/export.md b/docs/commands/builtin/export.md new file mode 100644 index 0000000..5501d9b --- /dev/null +++ b/docs/commands/builtin/export.md @@ -0,0 +1,52 @@ +# The export builtin command + +## Synopsis + + export [-fn] [NAME[=VALUE] ...] + export -p + +## Description + +The `export` builtin command is used to mark variables or functions +referenced by `NAME` for automatic export to the environment. If `NAME` +is a shell variable, a value `VALUE` can be assigned before exporting +it. + +### Options + + Option Description + -------- ------------------------------------------------------------------------------------------------------------ + `-f` refer to shell functions + `-n` remove the export property from any referenced `NAME` + `-p` print all exported variables, with `-f`, print all exported functions - all in a format re-usable as input + +An argument of `--` disables further option processing. + +### Return status + + Status Reason + -------- --------------------------- + 0 no error + !=0 invalid option + !=0 a given `NAME` is invalid + +## Examples + +Set the display to use when launching a GUI application (useful during +SSH sessions): + + export DISPLAY=":0" + +Set your default text editor (e.g. SublimeText): + + export EDITOR=subl + +## Portability considerations + +- in POSIX(r), only the `-p` option is specified +- in POSIX(r), only variables (with value assignment) are to be + exported, not shell functions + +## See also + +- [declare](/commands/builtin/declare) diff --git a/docs/commands/builtin/kill.md b/docs/commands/builtin/kill.md new file mode 100644 index 0000000..da12b52 --- /dev/null +++ b/docs/commands/builtin/kill.md @@ -0,0 +1,71 @@ +# The kill builtin command + +## Synopsis + + kill [-s SIGNAL | -n SIGNALNUMBER | -SIGNAL] PID|JOB + + kill -l|-L [SIGNAL...] + +## Description + +The `kill` command is used to send signals to processes specified by +their `PID` or their `JOB`-specification. + +The signal(s) to be specified can have the following formats: + +- Numerical: The signal is specified using its constant numeric value. + Be aware that not all systems have identical numbers for the + signals. +- Symbolic (long): The signal is specified using the same name that is + used for the constant/macro in the C API (`SIG`) +- Symbolic (short): The signal is specified using the name from the C + API without the `SIG`-prefix (``) + +Without any specified signal, the command sends the `SIGTERM`-signal. + +The `kill` command is a Bash builtin command instead of relying on the +external `kill` command of the operating system to + +- be able to use shell job specifications instead of Unix process IDs +- be able to send signals (\"kill something\") also, when your process + limit is reached + +### Options + + Option Description + ------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + `-s SIGNAL` specifies the signal to send + `-n SIGNALNUMBER` specifies the signal to send + `-SIGNAL` specifies the signal to send + `-l [SIGNAL...]` Lists supported/known signal numbers and their symbolic name. If `SIGNAL` is given, only list this signal, translated (if a number is given the symbolic name is printed, and vice versa) + `-L [SIGNAL...]` Same as `-l [SIGNAL]` (compatiblity option) + +### Return status + + Status Reason + -------- ----------------------------------------------------------------------------------------------------- + 0 no error/success + !=0 invalid option + !=0 invalid signal specification + !=0 error returned by the system function (e.g. insufficient permissions to send to a specific process) + +## Examples + +### List supported signals + + kill -l + +### Send KILL to a process ID + + kill -9 12345 + + kill -KILL 12345 + + kill -SIGKILL 12345 + +## Portability considerations + +- POSIX(R) and ISO C only standardize symbolic signal names (no + numbers) and a default action + +## See also diff --git a/docs/commands/builtin/let.md b/docs/commands/builtin/let.md new file mode 100644 index 0000000..ec1f189 --- /dev/null +++ b/docs/commands/builtin/let.md @@ -0,0 +1,111 @@ +# The let builtin command + +## Synopsis + + let arg [arg ...] + +## Description + +The `let` builtin command evaluates each supplied word from left to +right as an [arithmetic expression](/syntax/arith_expr) and returns an +exit code according to the truth value of the rightmost expression. + +- 0 (TRUE) when `arg` evaluated to not 0 (arithmetic \"true\") +- 1 (FALSE) when `arg` evaluated to 0 (arithmetic \"false\") + +For this return code mapping, please see [this +section](/syntax/arith_expr#arithmetic_expressions_and_return_codes). +They work in the same way as `((`. + +## Examples + +`let` is very similar to [((](/syntax/ccmd/arithmetic_eval) - the only +difference being `let` is a builtin (simple command), and `((` is a +compound command. The arguments to `let` are therefore subject to all +the same expansions and substitutions as any other simple command - +requiring proper quoting and escaping - whereas the contents of `((` +aren\'t subject to [word-splitting](/syntax/expansion/wordsplit) or +[pathname expansion](/syntax/expansion/globs) (almost never desirable +for arithmetic). For this reason, **the [arithmetic compound +command](/syntax/ccmd/arithmetic_eval) should generally be preferred +over `let`**. + + $ let 'b = a' "(a += 3) + $((a = 1)), b++" + $ echo "$a - $b - $?" + 4 - 2 - 0 + +Is equivalent to the [arithmetic evaluation compound +command](/syntax/ccmd/arithmetic_eval): + + $ (( b = a, (a += 3) + $((a = 1)), b++ )) + $ echo "$a - $b - $?" + 4 - 2 - 0 + +\ Remember that inside arithmetic evaluation contexts, all +other expansions are processed as usual (from left-to-right), and the +resulting text is evaluated as an arithmetic expression. Arithmetic +already has a way to control precedence using parentheses, so it\'s very +rare to need to nest arithmetic expansions within one another. It\'s +used above only to illustrate how this precedence works. \ + +Unlike `((`, being a simple command `let` has its own environment. In +Bash, built-ins that can set variables process any arithmetic under +their own environment, which makes the variable effectively \"local\" to +the builtin unless the variable is also set or modified by the builtin. +This differs in other shells, such as ksh93, where environment +assignments to regular builtins are always local even if the variable is +modified by the builtin. + + ~ $ ( y=1+1 let x=y; declare -p x y ) + declare -- x="2" + bash: declare: y: not found + + ~ $ ( y=1+1 let x=y++; declare -p x y ) + declare -- x="2" + declare -- y="3" + +This can be useful in certain situations where a temporary variable is +needed. + +## Portability considerations + +- the `let` command is not specified by POSIX(r). The portable + alternative is: `[ "$(( ))" -ne 0 ]`. To make portable + scripts simpler and cleaner, `let` can be defined as: `# POSIX + let() { + IFS=, command eval test '$(($*))' -ne 0 + } + ` Aside from differences in supported arithmetic features, this + should be identical to the Bash/Ksh `let`. +- It seems to be a common misunderstanding that `let` has some legacy + purpose. Both `let` and [[^1]](syntax/ccmd/arithmetic_eval) were + ksh88 features and almost identical in terms of portability as + everything that inherited one also tended to get the other. Don\'t + choose `let` over `((` expecting it to work in more places. +- [expr(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html#tag_20_42) + is a command one is likely to come across sooner or later. While it + is more \"standard\" than `let`, the above should always be + preferred. Both [arithmetic expansion](/syntax/arith_expr)s and the + `[` test operator are specified by POSIX(r) and satisfy almost all + of expr\'s use-cases. Unlike `let`, `expr` cannot assign directly to + bash variables but instead returns a result on stdout. `expr` takes + each operator it recognizes as a separate word and then concatenates + them into a single expression that\'s evaluated according to it\'s + own rules (which differ from shell arithmetic). `let` parses each + word it recieves on its own and evaluates it as an expression + without generating any output other than a return code. +- For unknown reasons, `let` is one of the Bash commands with special + parsing for arguments formatted like compound array assignments. + See: [eval](commands/builtin/eval#portability_considerations) for + details. There are no known practical uses for this. Parentheses are + treated as grouping operators and compound assignment is not + possible by arithmetic expressions. + +## See also + +- Internal: [arithmetic expansion](/syntax/expansion/arith) +- Internal: [arithmetic expressions](/syntax/arith_expr) +- Internal: [arithmetic evaluation compound + command](/syntax/ccmd/arithmetic_eval) + +[^1]: \... diff --git a/docs/commands/builtin/local.md b/docs/commands/builtin/local.md new file mode 100644 index 0000000..39b9b91 --- /dev/null +++ b/docs/commands/builtin/local.md @@ -0,0 +1,57 @@ +# The local builtin command + +## Synopsis + + local [option] name[=value] ... + +## Description + +`local` is identical to [declare](/commands/builtin/declare) in every +way, and takes all the same options, with 3 exceptions: + +- Usage outside of a function is an error. Both `declare` and `local` + within a function have the same effect on variable scope, including + the -g option. +- `local` with no options prints variable names and values in the same + format as `declare` with no options, except the variables are + filtered to print only locals that were set in the same scope from + which `local` was called. Variables in parent scopes are not + printed. +- If name is '-', the set of shell options is made local to the + function in which local is invoked: shell options changed using the + set builtin inside the function are restored to their original + values when the function returns. The restore is effected as if a + series of set commands were executed to restore the values that were + in place before the function. + +## Portability considerations + +- `local` is not specified by POSIX. Most bourne-like shells don\'t + have a builtin called `local`, but some such as `dash` and the + busybox shell do. + +```{=html} + +``` +- The behavior of function scope is not defined by POSIX, however + local variables are implemented widely by bourne-like shells, and + behavior differs substantially. Even the`dash` shell has local + variables. + +```{=html} + +``` +- In ksh93, using POSIX-style function definitions, `typeset` doesn\'t + set `local` variables, but rather acts upon variables of the + next-outermost scope (e.g. setting attributes). Using `typeset` + within functions defined using ksh `function name {` syntax, + variables follow roughly + [lexical-scoping](http://community.schemewiki.org/?lexical-scope), + except that functions themselves don\'t have scope, just like Bash. + This means that even functions defined within a \"function\'s + scope\" don\'t have access to non-local variables except through + `namerefs`. + +## See also + +- diff --git a/docs/commands/builtin/mapfile.md b/docs/commands/builtin/mapfile.md new file mode 100644 index 0000000..ffd4822 --- /dev/null +++ b/docs/commands/builtin/mapfile.md @@ -0,0 +1,221 @@ +# The mapfile builtin command + +## Synopsis + + mapfile [-n COUNT] [-O ORIGIN] [-s COUNT] [-t] [-u FD] [-C CALLBACK] [-c QUANTUM] [ARRAY] + + readarray [-n COUNT] [-O ORIGIN] [-s COUNT] [-t] [-u FD] [-C CALLBACK] [-c QUANTUM] [ARRAY] + +## Description + +This builtin is also accessible using the command name `readarray`. + +`mapfile` is one of the two builtin commands primarily intended for +handling standard input (the other being `read`). `mapfile` reads lines +of standard input and assigns each to the elements of an indexed array. +If no array name is given, the default array name is `MAPFILE`. The +target array must be a \"normal\" integer indexed array. + +`mapfile` returns success (0) unless an invalid option is given or the +given array `ARRAY` is set readonly. + + Option Description + --------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------- + `-c QUANTUM` Specifies the number of lines that have to be read between every call to the callback specified with `-C`. The default QUANTUM is 5000 + `-C CALLBACK` Specifies a callback. The string `CALLBACK` can be any shell code, the index of the array that will be assigned, and the line is appended at evaluation time. + `-n COUNT` Reads at most `COUNT` lines, then terminates. If `COUNT` is 0, then all lines are read (default). + `-O ORIGIN` Starts populating the given array `ARRAY` at the index `ORIGIN` rather than clearing it and starting at index 0. + `-s COUNT` Discards the first `COUNT` lines read. + `-t` Remove any trailing newline from a line read, before it is assigned to an array element. + `-u FD` Read from filedescriptor `FD` rather than standard input. + +While `mapfile` isn\'t a common or portable shell feature, it\'s +functionality will be familiar to many programmers. Almost all +programming languages (aside from shells) with support for compound +datatypes like arrays, and which handle open file objects in the +traditional way, have some analogous shortcut for easily reading all +lines of some input as a standard feature. In Bash, `mapfile` in itself +can\'t do anything that couldn\'t already be done using read and a loop, +and if portability is even a slight concern, should never be used. +However, it does *significantly* outperform a read loop, and can make +for shorter and cleaner code - especially convenient for interactive +use. + +## Examples + +Here\'s a real-world example of interactive use borrowed from Gentoo +workflow. Xorg updates require rebuilding drivers, and the +Gentoo-suggested command is less than ideal, so let\'s Bashify it. The +first command produces a list of packages, one per line. We can read +those into the array named \"args\" using `mapfile`, stripping trailing +newlines with the \'-t\' option. The resulting array is then expanded +into the arguments of the \"emerge\" command - an interface to Gentoo\'s +package manager. This type of usage can make for a safe and effective +replacement for xargs(1) in certain situations. Unlike xargs, all +arguments are guaranteed to be passed to a single invocation of the +command with no wordsplitting, pathname expansion, or other monkey +business. + + # eix --only-names -IC x11-drivers | { mapfile -t args; emerge -av1 "${args[@]}" <&1; } + +Note the use of command grouping to keep the emerge command inside the +pipe\'s subshell and within the scope of \"args\". Also note the unusual +redirection. This is because the -a flag makes emerge interactive, +asking the user for confirmation before continuing, and checking with +isatty(3) to abort if stdin isn\'t pointed at a terminal. Since stdin of +the entire command group is still coming from the pipe even though +mapfile has read all available input, we just borrow FD 1 as it just so +happens to be pointing where we want it. More on this over at greycat\'s +wiki: + +### The callback + +This is one of the more unusual features of a Bash builtin. As far as +I\'m able to tell, the exact behavior is as follows: If defined, as each +line is read, the code contained within the string argument to the -C +flag is evaluated and executed *before* the assignment of each array +element. There are no restrictions to this string, which can be any +arbitrary code, however, two additional \"words\" are automatically +appended to the end before evaluation: the index, and corresponding line +of data to be assigned to the next array element. Since all this happens +before assignment, the callback feature cannot be used to modify the +element to be assigned, though it can read and modify any array elements +already assigned. + +A very simple example might be to use it as a kind of progress bar. This +will print a dot for each line read. Note the escaped comment to hide +the appended words from printf. + + $ printf '%s\n' {1..5} | mapfile -c 1 -C 'printf . \#' ) + ..... + +Really, the intended usage is for the callback to just contain the name +of a function, with the extra words passed to it as arguments. If +you\'re going to use callbacks at all, this is probably the best way +because it allows for easy access to the arguments with no ugly \"code +in a string\". + + $ foo() { echo "|$1|"; }; mapfile -n 11 -c 2 -C 'foo' &$(( (${#x[@]} % 2) + 3 )) printf -- "%.sprefix %s"' x; } 3>outfile0 4>outfile1 + $ cat outfile{0,1} + prefix input1 + prefix input3 + prefix input5 + prefix input7 + prefix input9 + prefix input2 + prefix input4 + prefix input6 + prefix input8 + prefix input10 + +Since redirects are syntactically allowed anywhere in a command, we put +it before the printf to stay out of the way of additional arguments. +Rather than opening \"outfile\\" for appending on each call by +calculating the filename, open an FD for each first and calculate which +FD to send output to by measuring the size of x mod 2. The zero-width +format specification is used to absorb the index number argument. + +Another variation might be to add each of these lines to the elements of +separate arrays. I\'ll leave dissecting this one as an exercise for the +reader. This is quite the hack but illustrates some interesting +properties of printf -v and mapfile -C (which you should probably never +use in real code). + + $ y=( 'odd[j]' 'even[j++]' ); printf 'input%s\n' {1..10} | { mapfile -tc 1 -C 'printf -v "${y[${#x[@]} % 2]}" -- "%.sprefix %s"' x; printf '%s\n' "${odd[@]}" '' "${even[@]}"; } + prefix input1 + prefix input3 + prefix input5 + prefix input7 + prefix input9 + + prefix input2 + prefix input4 + prefix input6 + prefix input8 + prefix input10 + +This example based on yet another #bash question illustrates mapfile in +combination with read. The sample input is the heredoc to `main`. The +goal is to build a \"struct\" based upon records in the input file made +up of the numbers following the colon on each line. Every 3rd line is a +key followed by 2 corresponding fields. The showRecord function takes a +key and returns the record. + + #!/usr/bin/env bash + + showRecord() { + printf 'key[%d] = %d, %d\n' "$1" "${vals[@]:keys[$1]*2:2}" + } + + parseRecords() { + trap 'unset -f _f' RETURN + _f() { + local x + IFS=: read -r _ x + ((keys[x]=n++)) + } + local n + + _f + mapfile -tc2 -C _f "$1" + eval "$1"'=("${'"$1"'[@]##*:}")' # Return the array with some modification + } + + main() { + local -a keys vals + parseRecords vals + showRecord "$1" + } + + main "$1" <<-"EOF" + fabric.domain:123 + routex:1 + routey:2 + fabric.domain:321 + routex:6 + routey:4 + EOF + +For example, running `scriptname 321` would output `key[321] = 6, 4`. +Every 2 lines read by `mapfile`, the function `_f` is called, which +reads one additional line. Since the first line in the file is a key, +and `_f` is responsible for the keys, it gets called first so that +`mapfile` starts by reading the second line of input, calling `_f` with +each subsequent 2 iterations. The RETURN trap is unimportant. + +## Bugs + +- Early implementations were buggy. For example, `mapfile` filling the + readline history buffer with calls to the `CALLBACK`. This was fixed + in 4.1 beta. +- `mapfile -n` reads an extra line beyond the last line assigned to + the array, through Bash. [Fixed in + 4.2.35](ftp://ftp.gnu.org/gnu/bash/bash-4.2-patches/bash42-035). +- `mapfile` callbacks could cause a crash if the variable being + assigned is manipulated in certain ways. + . + Fixed in 4.3. + +## To Do + +- Create an implementation as a shell function that\'s portable + between Ksh, Zsh, and Bash (and possibly other bourne-like shells + with array support). + +## See also + +- [arrays](/syntax/arrays) +- [read](/commands/builtin/read) - If you don\'t know about this yet, + why are you reading this page? +- - It\'s FAQ 1 for a reason. diff --git a/docs/commands/builtin/printf.md b/docs/commands/builtin/printf.md new file mode 100644 index 0000000..422210c --- /dev/null +++ b/docs/commands/builtin/printf.md @@ -0,0 +1,476 @@ +# The printf command + +\
FIXME Stranger, this is a very big +topic that needs experience - please fill in missing information, extend +the descriptions, and correct the details if you can! \ \
[**Attention:**]{.underline} This is about the +Bash-builtin command `printf` - however, the description should be +nearly identical for an external command that follows POSIX(r). + +[GNU Awk](http://www.gnu.org/software/gawk/manual/gawk.html#Printf) +expects a comma after the format string and between each of the +arguments of a **printf** command. For examples, see: [code +snippet](printf?&#using_printf_inside_of_awk). \ + +Unlike other documentations, I don\'t want to redirect you to the manual +page for the `printf()` C function family. However, if you\'re more +experienced, that should be the most detailed description for the format +strings and modifiers. + +Due to conflicting historical implementations of the `echo` command, +POSIX(r) recommends that `printf` is preferred over `echo`. + +## General + +The `printf` command provides a method to print preformatted text +similar to the `printf()` system interface (C function). It\'s meant as +successor for `echo` and has far more features and possibilities. + +Beside other reasons, POSIX(r) has a very good argument to recommend it: +Both historical main flavours of the `echo` command are mutual +exclusive, they collide. A \"new\" command had to be invented to solve +the issue. + +## Syntax + + printf + +The text format is given in ``, while all arguments the +formatstring may point to are given after that, here, indicated by +``. + +Thus, a typical `printf`-call looks like: + + printf "Surname: %s\nName: %s\n" "$SURNAME" "$FIRSTNAME" + +where `"Surname: %s\nName: %s\n"` is the format specification, and the +two variables are passed as arguments, the `%s` in the formatstring +points to (for every format specifier you give, `printf` awaits one +argument!). + +### Options + + ---------- ------------------------------------------------------------------------------------------------------------------------------- + `-v VAR` If given, the output is assigned to the variable `VAR` instead of printed to `stdout` (comparable to `sprintf()` in some way) + ---------- ------------------------------------------------------------------------------------------------------------------------------- + +The `-v` Option can\'t assign directly to array indexes in Bash versions +older than Bash 4.1. + +\ In versions newer than 4.1, one must be careful when +performing expansions into the first non-option argument of printf as +this opens up the possibility of an easy code injection vulnerability. + + $ var='-vx[$(echo hi >&2)]'; printf "$var" hi; declare -p x + hi + declare -a x='([0]="hi")' + +\...where the echo can of course be replaced with any arbitrary command. +If you must, either specify a hard-coded format string or use \-- to +signal the end of options. The exact same issue also applies to +[read](commands/builtin/read), and a similar one to +[mapfile](commands/builtin/mapfile), though performing expansions into +their arguments is less common. \ + +### Arguments + +Of course in shell-meaning the arguments are just strings, however, the +common C-notations plus some additions for number-constants are +recognized to give a number-argument to `printf`: + + Number-Format Description + --------------- ------------------------------------------------------------------------------------------------------------------------ + `N` A normal decimal number + `0N` An octal number + `0xN` A hexadecimal number + `0XN` A hexadecimal number + `"X` (a literal double-quote infront of a character): interpreted as number (underlying codeset) **don\'t forget escaping** + `'X` (a literal single-quote infront of a character): interpreted as number (underlying codeset) **don\'t forget escaping** + +[**If more arguments than format specifiers**]{.underline} are present, +then the format string is re-used until the last argument is +interpreted. If fewer format specifiers than arguments are present, then +number-formats are set to zero, while string-formats are set to null +(empty). + +Take care to avoid [word splitting](/syntax/expansion/wordsplit), as +accidentally passing the wrong number of arguments can produce wildly +different and unexpected results. See [this article](/syntax/words). + +\ [**Again, attention:**]{.underline} When a numerical +format expects a number, the internal `printf`-command will use the +common Bash arithmetic rules regarding the base. A command like the +following example **will** throw an error, since `08` is not a valid +octal number (`00` to `07`!): + + printf '%d\n' 08 + +\ + +### Format strings + +The format string interpretion is derived from the C `printf()` function +family. Only format specifiers that end in one of the letters +`diouxXfeEgGaAcs` are recognized. + +To print a literal `%` (percent-sign), use `%%` in the format string. + +[**Again:**]{.underline} Every format specifier expects an associated +argument provided! + +These specifiers have different names, depending who you ask. But they +all mean the same: A placeholder for data with a specified format: + +- format placeholder +- conversion specification +- formatting token +- \... + + Format Description + -------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + `%b` Print the associated argument while interpreting backslash escapes in there + `%q` Print the associated argument **shell-quoted**, reusable as input + `%d` Print the associated argument as **signed decimal** number + `%i` Same as `%d` + `%o` Print the associated argument as **unsigned octal** number + `%u` Print the associated argument as **unsigned decimal** number + `%x` Print the associated argument as **unsigned hexadecimal** number with lower-case hex-digits (a-f) + `%X` Same as `%x`, but with upper-case hex-digits (A-F) + `%f` Interpret and print the associated argument as **floating point** number + `%e` Interpret the associated argument as **double**, and print it in `±e` format + `%E` Same as `%e`, but with an upper-case `E` in the printed format + `%g` Interprets the associated argument as **double**, but prints it like `%f` or `%e` + `%G` Same as `%g`, but print it like `%E` + `%c` Interprets the associated argument as **char**: only the first character of a given argument is printed + `%s` Interprets the associated argument literally as string + `%n` Assigns the number of characters printed so far to the variable named in the corresponding argument. Can\'t specify an array index. If the given name is already an array, the value is assigned to the zeroth element. + `%a` Interprets the associated argument as **double**, and prints it in the form of a C99 [hexadecimal floating-point literal](http://www.exploringbinary.com/hexadecimal-floating-point-constants/). + `%A` Same as `%a`, but print it like `%E` + `%(FORMAT)T` output the date-time string resulting from using `FORMAT` as a format string for `strftime(3)`. The associated argument is the number of seconds since Epoch, or `-1` (current time) or `-2` (shell startup time). If no corresponding argument is supplies, the current time is used as default + `%%` No conversion is done. Produces a `%` (percent sign) + +Some of the mentioned format specifiers can modify their behaviour by +getting a format modifier: + +### Modifiers + +To be more flexible in the output of numbers and strings, the `printf` +command allows format modifiers. These are specified **between** the +introductory `%` and the character that specifies the format: + + printf "%50s\n" "This field is 50 characters wide..." + +#### Field and printing modifiers + + Field output format + --------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + `` **Any number**: Specifies a **minimum field width**, if the text to print is shorter, it\'s padded with spaces, if the text is longer, the field is expanded + `.` **The dot**: Together with a field width, the field is **not** expanded when the text is longer, the text is truncated instead. \"`%.s`\" is an undocumented equivalent for \"`%.0s`\", which will force a field width of zero, effectively hiding the field from output + `*` **The asterisk**: the width is given as argument before the string or number. Usage (the \"`*`\" corresponds to the \"`20`\"): `printf "%*s\n" 20 "test string"` + `#` \"Alternative format\" for numbers: see table below + `-` **Left-bound** text printing in the field (standard is **right-bound**) + `0` Pads numbers with zeros, not spaces + `` Pad a positive number with a space, where a minus (`-`) is for negative numbers + `+` Prints all numbers **signed** (`+` for positive, `-` for negative) + `'` For decimal conversions, the thousands grouping separator is applied to the integer portion of the output according to the current LC_NUMERIC + +[**The \"alternative format\" modifier `#`:**]{.underline} + + Alternative Format + -------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------- + `%#o` The octal number is printed with a leading zero, unless it\'s zero itself + `%#x`, `%#X` The hex number is printed with a leading \"`0x`\"/\"`0X`\", unless it\'s zero + `%#g`, `%#G` The float number is printed with **trailing zeros** until the number of digits for the current precision is reached (usually trailing zeros are not printed) + all number formats except `%d`, `%o`, `%x`, `%X` Always print a decimal point in the output, even if no digits follow it + +#### Precision + +The precision for a floating- or double-number can be specified by using +`.`, where `` is the number of digits for precision. If +`` is an asterisk (`*`), the precision is read from the argument +that precedes the number to print, like (prints 4,3000000000): + + printf "%.*f\n" 10 4,3 + +The format `.*N` to specify the N\'th argument for precision does not +work in Bash. + +For strings, the precision specifies the maximum number of characters to +print (i.e., the maximum field width). For integers, it specifies the +number of digits to print (zero-padding!). + +### Escape codes + +These are interpreted if used anywhere in the format string, or in an +argument corresponding to a `%b` format. + + Code Description + ---------------- --------------------------------------------------------------------------------------------------------------------------- + `\\` Prints the character `\` (backslash) + `\a` Prints the alert character (ASCII code 7 decimal) + `\b` Prints a backspace + `\f` Prints a form-feed + `\n` Prints a newline + `\r` Prints a carriage-return + `\t` Prints a horizontal tabulator + `\v` Prints a vertical tabulator + `\"` Prints a `'` + `\?` Prints a `?` + `\` Interprets `` as **octal** number and prints the corresponding character from the character set + `\0` same as `\` + `\x` Interprets `` as **hexadecimal** number and prints the corresponding character from the character set (**3 digits**) + `\u` same as `\x`, but **4 digits** + `\U` same as `\x`, but **8 digits** + +The following additional escape and extra rules apply only to arguments +associated with a `%b` format: + + ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------- + `\c` Terminate output similarly to the `\c` escape used by `echo -e`. printf produces no additional output after coming across a `\c` escape in a `%b` argument. + ------ ------------------------------------------------------------------------------------------------------------------------------------------------------------- + +- Backslashes in the escapes: `\'`, `\"`, and `\?` are not removed. +- Octal escapes beginning with `\0` may contain up to four digits. + (POSIX specifies up to three). + +These are also respects in which `%b` differs from the escapes used by +[\$\'\...\'](syntax/quoting#ansi_c_like_strings) style quoting. + +## Examples + +### Snipplets + +- print the decimal representation of a hexadecimal number (preserve + the sign) + - `printf "%d\n" 0x41` + - `printf "%d\n" -0x41` + - `printf "%+d\n" 0x41` +- print the octal representation of a decimal number + - `printf "%o\n" 65` + - `printf "%05o\n" 65` (5 characters width, padded with zeros) +- this prints a 0, since no argument is specified + - `printf "%d\n"` +- print the code number of the character `A` + - `printf "%d\n" \'A` + - `printf "%d\n" "'A"` +- Generate a greeting banner and assign it to the variable `GREETER` + - `printf -v GREETER "Hello %s" "$LOGNAME"` +- Print a text at the end of the line, using `tput` to get the current + line width + - `printf "%*s\n" $(tput cols) "Hello world!"` + +### Small code table + +This small loop prints all numbers from 0 to 127 in + +- decimal +- octal +- hex + +```{=html} + +``` + for ((x=0; x <= 127; x++)); do + printf '%3d | %04o | 0x%02x\n' "$x" "$x" "$x" + done + +### Ensure well-formatted MAC address + +This code here will take a common MAC address and rewrite it into a +well-known format (regarding leading zeros or upper/lowercase of the hex +digits, \...): + + the_mac="0:13:ce:7:7a:ad" + + # lowercase hex digits + the_mac="$(printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${the_mac//:/ 0x})" + + # or the uppercase-digits variant + the_mac="$(printf "%02X:%02X:%02X:%02X:%02X:%02X" 0x${the_mac//:/ 0x})" + +### Replacement echo + +This code was found in Solaris manpage for echo(1). + +Solaris version of `/usr/bin/echo` is equivalent to: + + printf "%b\n" "$*" + +Solaris `/usr/ucb/echo` is equivalent to: + + if [ "X$1" = "X-n" ] + then + shift + printf "%s" "$*" + else + printf "%s\n" "$*" + fi + +### prargs Implementation + +Working off the replacement echo, here is a terse implementation of +prargs: + + printf '"%b"\n' "$0" "$@" | nl -v0 -s": " + +### repeating a character (for example to print a line) + +A small trick: Combining printf and parameter expansion to draw a line + + length=40 + printf -v line '%*s' "$length" + echo ${line// /-} + +or: + + length=40 + eval printf -v line '%.0s-' {1..$length} + +### Replacement for some calls to date(1) + +The `%(...)T` format string is a direct interface to `strftime(3)`. + + $ printf 'This is week %(%U/%Y)T.\n' -1 + This is week 52/2010. + +Please read the manpage of `strftime(3)` to get more information about +the supported formats. + +## differences from awk printf + +Awk also derives its *printf()* function from C, and therefore has +similar format specifiers. However, in all versions of awk the space +character is used as a string concatenation operator, so it cannot be +used as an argument separator. **Arguments to awk printf must be +separated by commas.** Some versions of awk do not require printf +arguments to be surrounded by parentheses, but you should use them +anyway to provide portability. + +In the following example, the two strings are concatenated by the +intervening space so that no argument remains to fill the format. + + + $ echo "Foo" | awk '{ printf "%s\n" $1 }' + awk: (FILENAME=- FNR=1) fatal: not enough arguments to satisfy format string + `%s + Foo' + ^ ran out for this one + +Simply replacing the space with a comma and adding parentheses yields +correct awk syntax. + + $ echo "Foo" | awk '{ printf( "%s\n", $1 ) }' + Foo + +With appropriate metacharacter escaping the bash printf can be called +from inside awk (as from perl and other languages that support shell +callout) as long as you don\'t care about program efficiency or +readability. + + echo "Foo" | awk '{ system( "printf \"%s\\n \" \"" $1 "\"" ) }' + Foo + +## Differences from C, and portability considerations + +- The a, A, e, E, f, F, g, and G conversions are supported by Bash, + but not required by POSIX. + +```{=html} + +``` +- There is no wide-character support (wprintf). For instance, if you + use `%c`, you\'re actually asking for the first byte of the + argument. Likewise, the maximum field width modifier (dot) in + combination with `%s` goes by bytes, not characters. This limits + some of printf\'s functionality to working with ascii only. ksh93\'s + `printf` supports the `L` modifier with `%s` and `%c` (but so far + not `%S` or `%C`) in order to treat precision as character width, + not byte count. zsh appears to adjust itself dynamically based upon + `LANG` and `LC_CTYPE`. If `LC_CTYPE=C`, zsh will throw \"character + not in range\" errors, and otherwise supports wide characters + automatically if a variable-width encoding is set for the current + locale. + +```{=html} + +``` +- Bash recognizes and skips over any characters present in the length + modifiers specified by POSIX during format string parsing. + +``` c|builtins/printf.def +#define LENMODS "hjlLtz" +... +/* skip possible format modifiers */ +modstart = fmt; +while (*fmt && strchr (LENMODS, *fmt)) +fmt++; +``` + +- mksh has no built-in printf by default (usually). There is an + unsupported compile-time option to include a very poor, basically + unusable implementation. For the most part you must rely upon the + system\'s `/usr/bin/printf` or equivalent. The mksh maintainer + recommends using `print`. The development version (post- R40f) adds + a new parameter expansion in the form of `${name@Q}` which fills the + role of `printf %q` \-- expanding in a shell-escaped format. + +```{=html} + +``` +- ksh93 optimizes builtins run from within a command substitution and + which have no redirections to run in the shell\'s process. Therefore + the `printf -v` functionality can be closely matched by + `var=$(printf ...)` without a big performance hit. + +```{=html} + +``` + # Illustrates Bash-like behavior. Redefining printf is usually unnecessary / not recommended. + function printf { + case $1 in + -v) + shift + nameref x=$1 + shift + x=$(command printf "$@") + ;; + *) + command printf "$@" + esac + } + builtin cut + print $$ + printf -v 'foo[2]' '%d\n' "$(cut -d ' ' -f 1 /proc/self/stat)" + typeset -p foo + # 22461 + # typeset -a foo=([2]=22461) + +- The optional Bash loadable `print` may be useful for ksh + compatibility and to overcome some of + [echo](commands/builtin/echo)\'s portability pitfalls. Bash, ksh93, + and zsh\'s `print` have an `-f` option which takes a `printf` format + string and applies it to the remaining arguments. Bash lists the + synopsis as: + `print: print [-Rnprs] [-u unit] [-f format] [arguments]`. However, + only `-Rrnfu` are actually functional. Internally, `-p` is a noop + (it doesn\'t tie in with Bash coprocs at all), and `-s` only sets a + flag but has no effect. `-Cev` are unimplemented. + +```{=html} + +``` +- Assigning to variables: The `printf -v` way is slightly different to + the way using command-substitution. [Command + substitution](/syntax/expansion/cmdsubst) removes trailing newlines + before substituting the text, `printf -v` preserves all output. + +## See also + +- SUS: [printf + utility](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html) + and [printf() + function](http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html) +- [Code snip: Print a horizontal + line](/snipplets/print_horizontal_line) uses some `printf` examples +- [Greg\'s BashFAQ 18: How can I use numbers with leading zeros in a + loop, e.g., 01, 02?](BashFAQ>018) diff --git a/docs/commands/builtin/read.md b/docs/commands/builtin/read.md new file mode 100644 index 0000000..fe3f406 --- /dev/null +++ b/docs/commands/builtin/read.md @@ -0,0 +1,269 @@ +# The read builtin command + +*read something about read here!* + +## Synopsis + + read [-ers] [-u ] [-t ] [-p ] [-a ] [-n ] [-N ] [-d ] [-i ] [] + +## Description + +The `read` builtin reads **one line** of data (text, user input, \...) +from standard input or a supplied filedescriptor number into one or more +variables named by ``. + +Since Bash 4.3-alpha, `read` skips any `NUL` (ASCII code 0) characters +in input. + +If `` is given, the line is word-split using +[IFS](/syntax/shellvars#IFS) variable, and every word is assigned to one +``. The remaining words are all assigned to the last `` if +more words than variable names are present. + +\ If no `` is given, the whole line +read (without performing word-splitting!) is assigned to the shell +variable [REPLY](/syntax/shellvars#REPLY). Then, `REPLY` really contains +the line as it was read, without stripping pre- and postfix spaces and +other things! + + while read -r; do + printf '"%s"\n' "$REPLY" + done <<<" a line with prefix and postfix space " + +\ + +If a timeout is given, or if the shell variable +[TMOUT](/syntax/shellvars#TMOUT) is set, it is counted from initially +waiting for input until the completion of input (i.e. until the complete +line is read). That means the timeout can occur during input, too. + +### Options + + Option Description + ---------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + `-a ` read the data word-wise into the specified array `` instead of normal variables + `-d ` recognize `` as data-end, rather than `` + `-e` on interactive shells: use Bash\'s readline interface to read the data. Since version 5.1-alpha, this can also be used on specified file descriptors using `-u` + `-i ` preloads the input buffer with text from ``, only works when Readline (`-e`) is used + `-n ` reads `` characters of input, then quits + `-N ` reads `` characters of input, *ignoring any delimiter*, then quits + `-p ` the prompt string `` is output (without a trailing automatic newline) before the read is performed + `-r` raw input - **disables** interpretion of **backslash escapes** and **line-continuation** in the read data + `-s` secure input - don\'t echo input if on a terminal (passwords!) + `-t ` wait for data `` seconds, then quit (exit code 1). Fractional seconds (\"5.33\") are allowed since Bash 4. A value of 0 immediately returns and indicates if data is waiting in the exit code. Timeout is indicated by an exit code greater than 128. If timeout arrives before data is read completely (before end-of-line), the partial data is saved. + `-u ` use the filedescriptor number `` rather than `stdin` (0) + +When both, `-a ` and a variable name `` is given, then the +array is set, but not the variable. + +Of course it\'s valid to set individual array elements without using +`-a`: + + read MYARRAY[5] + +\ + +Reading into array elements using the syntax above **may cause [pathname +expansion](/syntax/expansion/globs) to occur**. + +Example: You are in a directory with a file named `x1`, and you want to +read into an array `x`, index `1` with + + read x[1] + +then pathname expansion will expand to the filename `x1` and break your +processing! + +Even worse, if `nullglob` is set, your array/index will disappear. + +To avoid this, either **disable pathname expansion** or **quote** the +array name and index: + + read 'x[1]' + +\ + +### Return status + + Status Reason + -------- --------------------------------------------------- + 0 no error + 0 error when assigning to a read-only variable [^1] + 2 invalid option + \>128 timeout (see `-t`) + !=0 invalid filedescriptor supplied to `-u` + !=0 end-of-file reached + +### read without -r + +Essentially all you need to know about `-r` is to **ALWAYS** use it. The +exact behavior you get without `-r` is completely useless even for weird +purposes. It basically allows the escaping of input which matches +something in IFS, and also escapes line continuations. It\'s explained +pretty well in the [POSIX +read](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html#tag_20_109) +spec. + + 2012-05-23 13:48:31 geirha it should only remove the backslashes, not change \n and \t and such into newlines and tabs + 2012-05-23 13:49:00 ormaaj so that's what read without -r does? + 2012-05-23 13:49:16 geirha no, -r doesn't remove the backslashes + 2012-05-23 13:49:34 ormaaj I thought read <<<'str' was equivalent to read -r <<<$'str' + 2012-05-23 13:49:38 geirha # read x y <<< 'foo\ bar baz'; echo "<$x><$y>" + 2012-05-23 13:49:40 shbot geirha: + 2012-05-23 13:50:32 geirha no, read without -r is mostly pointless. Damn bourne + 2012-05-23 13:51:08 ormaaj So it's mostly (entirely) used to escape spaces + 2012-05-23 13:51:24 ormaaj and insert newlines + 2012-05-23 13:51:47 geirha ormaaj: you mostly get the same effect as using \ at the prompt + 2012-05-23 13:52:04 geirha echo \" outputs a " , read x <<< '\"' reads a " + 2012-05-23 13:52:32 ormaaj oh weird + 2012-05-23 13:52:46 * ormaaj struggles to think of a point to that... + 2012-05-23 13:53:01 geirha ormaaj: ask Bourne :P + 2012-05-23 13:53:20 geirha (not Jason) + 2012-05-23 13:53:56 ormaaj hm thanks anyway :) + +## Examples + +### Rudimentary cat replacement + +A rudimentary replacement for the `cat` command: read lines of input +from a file and print them on the terminal. + + opossum() { + while read -r; do + printf "%s\n" "$REPLY" + done <"$1" + } + +[**Note:**]{.underline} Here, `read -r` and the default `REPLY` is used, +because we want to have the real literal line, without any mangeling. +`printf` is used, because (depending on settings), `echo` may interpret +some baskslash-escapes or switches (like `-n`). + +### Press any key\... + +Remember the MSDOS `pause` command? Here\'s something similar: + + pause() { + local dummy + read -s -r -p "Press any key to continue..." -n 1 dummy + } + +Notes: + +- `-s` to suppress terminal echo (printing) +- `-r` to not interpret special characters (like waiting for a second + character if somebody presses the backslash) + +### Reading Columns + +#### Simple Split + +Read can be used to split a string: + + var="one two three" + read -r col1 col2 col3 <<< "$var" + printf "col1: %s col2: %s col3 %s\n" "$col1" "$col2" "$col3" + +Take care that you cannot use a pipe: + + echo "$var" | read col1 col2 col3 # does not work! + printf "col1: %s col2: %s col3 %s\n" "$col1" "$col2" "$col3" + +Why? because the commands of the pipe run in subshells that cannot +modify the parent shell. As a result, the variables `col1`, `col2` and +`col3` of the parent shell are not modified (see article: +[processtree](/scripting/processtree)). + +If the variable has more fields than there are variables, the last +variable get the remaining of the line: + + read col1 col2 col3 <<< "one two three four" + printf "%s\n" "$col3" #prints three four + +#### Changing The Separator + +By default reads separates the line in fields using spaces or tabs. You +can modify this using the *special variable* +[IFS](/syntax/shellvars#IFS), the Internal Field Separator. + + IFS=":" read -r col1 col2 <<< "hello:world" + printf "col1: %s col2: %s\n" "$col1" "$col2" + +Here we use the `var=value command` syntax to set the environment of +`read` temporarily. We could have set `IFS` normally, but then we would +have to take care to save its value and restore it afterward +(`OLD=$IFS IFS=":"; read ....;IFS=$OLD`). + +The default `IFS` is special in that 2 fields can be separated by one or +more space or tab. When you set `IFS` to something besides whitespace +(space or tab), the fields are separated by **exactly** one character: + + IFS=":" read -r col1 col2 col3 <<< "hello::world" + printf "col1: %s col2: %s col3 %s\n" "$col1" "$col2" "$col3" + +See how the `::` in the middle infact defines an additional *empty +field*. + +The fields are separated by exactly one character, but the character can +be different between each field: + + IFS=":|@" read -r col1 col2 col3 col4 <<< "hello:world|in@bash" + printf "col1: %s col2: %s col3 %s col4 %s\n" "$col1" "$col2" "$col3" "$col4" + +### Are you sure? + + asksure() { + echo -n "Are you sure (Y/N)? " + while read -r -n 1 -s answer; do + if [[ $answer = [YyNn] ]]; then + [[ $answer = [Yy] ]] && retval=0 + [[ $answer = [Nn] ]] && retval=1 + break + fi + done + + echo # just a final linefeed, optics... + + return $retval + } + + ### using it + if asksure; then + echo "Okay, performing rm -rf / then, master...." + else + echo "Pfff..." + fi + +### Ask for a path with a default value + +[**Note:**]{.underline} The `-i` option was introduced with Bash 4 + + read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH + +The user will be prompted, he can just accept the default, or edit it. + +### Multichar-IFS: Parsing a simple date/time string + +Here, `IFS` contains both, a colon and a space. The fields of the +date/time string are recognized correctly. + + datetime="2008:07:04 00:34:45" + IFS=": " read -r year month day hour minute second <<< "$datetime" + +## Portability considerations + +- POSIX(r) only specified the `-r` option (raw read); `-r` is not only + POSIX, you can find it in earlier Bourne source code +- POSIX(r) doesn\'t support arrays +- `REPLY` is not POSIX(r), you need to set `IFS` to the empty string + to get the whole line for shells that don\'t know `REPLY`. + `while IFS= read -r line; do + ... + done < text.txt + ` + +## See also + +- Internal: [The printf builtin command](/commands/builtin/printf) + +[^1]: fixed in 4.2-rc1 diff --git a/docs/commands/builtin/readonly.md b/docs/commands/builtin/readonly.md new file mode 100644 index 0000000..140512f --- /dev/null +++ b/docs/commands/builtin/readonly.md @@ -0,0 +1,45 @@ +# The readonly builtin command + +## Synopsis + + readonly [-p] [-a] [-A] [-f] [NAME[=VALUE] ...] + +## Description + +The `readonly` builtin command is used to mark variables or functions as +read-only, which means unchangeable. This implies that it can\'t be +unset anymore. A `readonly` variable may not be redefined in child +scopes. A readonly global may not be redefined as a function local +variable. Simple command environment assignments may not reference +readonly variables. + +### Options + + Option Description + -------- ------------------------------------------------------------------------------------------------------------------------ + `-a` refer to normal arrays + `-A` refer to associative arrays + `-f` refer to functions + `-p` print all read-only variables or functions, `-a`, `-A` and `-f` can be used to filter. The output is reusable as input + +An argument of `--` disables further option processing. + +### Return status + + Status Reason + -------- -------------------------------- + 0 no error + !=0 invalid option + !=0 invalid combination of options + !=0 a given `NAME` is invalid + +## Examples + +## Portability considerations + +- in POSIX(r), only the `-p` option is specified + +## See also + +- [declare](/commands/builtin/declare) +- [unset](/commands/builtin/unset) diff --git a/docs/commands/builtin/return.md b/docs/commands/builtin/return.md new file mode 100644 index 0000000..f4adca4 --- /dev/null +++ b/docs/commands/builtin/return.md @@ -0,0 +1,35 @@ +# The return builtin command + +## Synopsis + + return [N] + +## Description + +The `return` command returns from a shell function. + +If `N` is given, the return code to the caller is set to `N`. If not, +the returned status the the status of the most recently executed command +(i.e. `$?`). + +### Options + +There are no options. + +### Exit status + +If everything is okay, the `return` command doesn\'t come back. If it +comes back, there was a problem in doing the return. + + Status Reason + -------- ------------------------------------------------------------------------- + 1 `return` was called while not being in a shell function or sourced file + +## Examples + +## Portability considerations + +## See also + +- [The exit builtin command](/commands/builtin/exit) +- [The exit status](/dict/terms/exit_status) diff --git a/docs/commands/builtin/set.md b/docs/commands/builtin/set.md new file mode 100644 index 0000000..7aff0d0 --- /dev/null +++ b/docs/commands/builtin/set.md @@ -0,0 +1,81 @@ +# The set builtin command + +FIXME incomplete - text, examples, maybe extended description + +## Synopsis + + set [--abefhkmnptuvxBCHP] <-o OPTIONNAME> [-][--] + +## Description + +`set` is primarily made to + +- set the positional parameters (see [handling positional + parameters](/scripting/posparams)) to `` +- set shell attributes with short options (see below) +- set shell attributes with long option names (see below) + +Without any options, `set` displays all shell- and environment-variables +(only is POSIX-mode) in a re-usable format `NAME=VALUE`. + +### Attributes + +All attributes below can be switched on using `-X` and switched off +using `+X`. This is done because of the historical meaning of the `-` to +set flags (true for most commands on UNIX(r)). + + Flag Optionname Description + ------ ---------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + `-a` `allexport` Automatically mark new and altered variables to be exported to subsequent environments. + `-b` `notify` Don\'t wait for the next prompt to print when showing the reports for a terminated background job (only with job control) + `-e` `errexit` When set, the shell exits when a simple command in a command list exits non-zero (`FALSE`). This is not done in situations, where the exit code is already checked (`if`, `while`, `until`, `||`, `&&`) + `-f` `noglob` Disable [pathname expansion](/syntax/expansion/globs) (globbing) + `-h` `hashall` Remembers the location of commands when they\'re called (hashing). Enabled by default. + `-k` `keyword` Allows to place environment-assignments everywhere in the commandline, not only infront of the called command. + `-m` `monitor` **Monitor mode**. With job control, a short descriptive line is printed when a backgroud job ends. Default is \"on\" for interactive shells (with job control). + `-n` `noexec` Read and parse but **do not execute commands** - useful for checking scripts for syntax errors. Ignored by interactive shells. + `-o` Set/unset attributes with long option names, e.g. `set -o noglob`. The long option names are in the second column of this table. If no option name is given, all options are printed with their current status. + `-p` `privileged` Turn on privileged mode. + `-t` `onecmd` Exit after reading and executing **one** command. + `-u` `nounset` Treat unset variables as an error when performing parameter expansion. Non-interactive shells exit on this error. + `-v` `verbose` Print shell input lines as they are read - useful for debugging. + `-x` `xtrace` Print commands just before execution - with all expansions and substitutions done, and words marked - useful for debugging. + `-B` `braceexpand` The shell performs [brace expansion](/syntax/expansion/brace) This is on by default. + `-C` \`noclobber` Don\'t overwrite files on redirection operations. You can override that by specifying the `>|` redirection operator when needed. See [redirection](/syntax/redirection) + `-E` `errtrace` `ERR`-traps are inherited by by shell functions, command substitutions, and commands executed in a subshell environment. + `-H` `histexpand` Enable `!`-style history expansion. Defaults to `on` for interactive shells. + `-P` `physical` Don\'t follow symlinks when changing directories - use the physical filesystem structure. + `-T` `functrace` `DEBUG`- and `RETURN`-traps are inherited by subsequent environments, like `-E` for `ERR` trap. + `-` \"End of options\" - all following arguments are assigned to the positional parameters, even when they begin with a dash. `-x` and `-v` options are turned off. Positional parameters are unchanged (unlike using `--`!) when no further arguments are given. + `--` If no arguments follow, the positional parameters are unset. With arguments, the positional parameters are set, even if the strings begin with a `-` (dash) like an option. + Long options usable with `-o` without a short equivalent + `emacs` Use an emacs-style command line editing interface. This is enabled by default when the shell is interactive, unless the shell is started with `--noediting` option. + `history` If set, command historization is done (enabled by default on interactive shells) + `ignoreeof` The effect is as if the shell command `IGNOREEOF=10` had been executed. See [shell variables](/syntax/shellvars). + `nolog` **(currently ignored)** + `pipefail` If set, the exit code from a pipeline is different from the normal (\"last command in pipeline\") behaviour: `TRUE` when no command failed, `FALSE` when something failed (code of the rightmost command that failed) + `posix` When set, Bash runs in POSIX mode. + `vi` Enables a `vi`-style command line editing interface. + +## Examples + +Tag a part of a shell script to output debugging information (`-x`): + +``` bash +#!/bin/bash +... +set -x # on +... +set +x # off +... +``` + +## Portability considerations + +`set` and its basic behaviour and options are specified by POSIX(r). +However, options that influence Bash-specific things are not portable, +naturally. + +## See also + +- Internal: [The shopt builtin command](/commands/builtin/shopt) diff --git a/docs/commands/builtin/shift.md b/docs/commands/builtin/shift.md new file mode 100644 index 0000000..7a1b1f3 --- /dev/null +++ b/docs/commands/builtin/shift.md @@ -0,0 +1,88 @@ +# The shift builtin command + +## Synopsis + + shift [n] + +## Description + +The `shift` builtin command is used to \"shift\" the positional +parameters by the given number `n` or by 1, if no number is given. + +This means, the number and the position of the positional parameters are +changed. The very first positional parameter is discarded, the second +becomes the first one, etc. + +Imagine the following set of positional parameters (`$1` to `$4`): + + 1 This + --- ------ + 2 is + 3 a + 4 test + +When you use `shift 1`, they will be changed to: + + 1 is + --- ------ + 2 a + 3 test + +The [special parameter](/syntax/shellvars#special_parameters) `$#` will +reflect the final number of positional parameters. + +If the number given is 0, no changes are made to the positional +parameters. + +### Options + +There are no options. + +### Return status + + Status Reason + -------- ----------------------------------------------------------------------------------------------------- + 0 no error + 1 non-numeric argument + 1 given number (or the default 1) is bigger than the number of actually present positional parameters + 1 given number is negative + +## Examples + +## Portability considerations + +- The `shift` builtin command is specified by POSIX(r). +- Many shells will throw a fatal error when attempting to `shift` more + than the number of positional parameters. **POSIX does not require + that behavior**. Bash (even in POSIX mode) and Zsh return 1 when + there are no args, and no error output is produced unless the + [shift_verbose](internals/shell_options#shift_verbose) + [shopt](commands/builtin/shopt) option is enabled. Ksh93, pdksh, + posh, mksh, and dash, all throw useless fatal shell + errors.`$ dash -c 'f() { if shift; then echo "$1"; else echo "no args"; fi; }; f' + dash: 1: shift: can't shift that many + ` In most shells, you can work around this problem using the + [command](/commands/builtin/command) builtin to suppress fatal + errors caused by *special builtins*. \ \$ dash -c \'f() { if + command shift 2\>/dev/null; then echo \"\$1\"; else echo \"no + args\"; fi; }; f\' + +no args \ While, POSIX requires this behavior, it isn\'t very +obvious and some shells don\'t do it correctly. To work around this, you +can use something like: + +\ \$ mksh -c \'f() { if ! \${1+false} && shift; then echo +\"\$1\"; else echo \"no args\"; fi; }; f\' no args \ ~~The mksh +maintainer refuses to change either the `shift` or `command` builtins.~~ +[Fixed](https://github.com/MirBSD/mksh/commit/996e05548ab82f7ef2dea61f109cc7b6d13837fa). +(Thanks!) + +- Perhaps almost as bad as the above, busybox sh\'s `shift` always + returns success, even when attempting to shift beyond the final + argument. \ \$ bb -c \'f() { if shift; then echo \"\$1\"; + else echo \"no args\"; fi; }; f\' + +(no output) \ The above mksh workaround will work in this case +too. + +## See also diff --git a/docs/commands/builtin/shopt.md b/docs/commands/builtin/shopt.md new file mode 100644 index 0000000..96ed762 --- /dev/null +++ b/docs/commands/builtin/shopt.md @@ -0,0 +1,51 @@ +# The shopt builtin command + +The `shopt` builtin manages [shell options](/internals/shell_options), a +set of boolean (`on`/`off`) configuration variables that control the +behaviour of the shell. + +## Synopsis + + shopt [-pqsu] [-o] + +## Description + +Note: Some of these options and other shell options can also be set with +[the set builtin](/commands/builtin/set). + +### Options + + Option Description + -------- ----------------------------------------------------------------------------------------------------------------------------- + `-o` Restrict the values of `` to only those also known by [the set builtin](/commands/builtin/set) + `-p` Print all shell options and their current value. **Default**. + `-q` Quiet mode. Set exit code if named option is set. For multiple options: `TRUE` if all options are set, `FALSE` otherwise + `-s` Enable ([s]{.underline}et) the shell options named by `` or list all *enabled* options if no names are given + `-u` Disabe ([u]{.underline}nset) the shell options named by `` or list all *disabled* options if no names are given + +As noted above, if only `-s` or `-u` are given without any option names, +only the currently enabled (`-s`) or disabled (`-u`) options are +printed. + +### Exit code + +When listing options, the exit code is `TRUE` (0), if all options are +enabled, `FALSE` otherwise. + +When setting/unsetting an option, the exit code is `TRUE` unless the +named option doesn\'t exitst. + +## Examples + +Enable the `nullglob` option: + + shopt -s nullglob + +## Portability considerations + +The `shopt` command is not portable accross different shells. + +## See also + +- Internal: [The set builtin command](/commands/builtin/set) +- Internal: [List of shell options](/internals/shell_options) diff --git a/docs/commands/builtin/trap.md b/docs/commands/builtin/trap.md new file mode 100644 index 0000000..ebfd925 --- /dev/null +++ b/docs/commands/builtin/trap.md @@ -0,0 +1,72 @@ +# The trap builtin command + +## Synopsis + + trap [-lp] [[ARGUMENT] SIGNAL] + +## Description + +The `trap` command is used to \"trap\" signals and other events. In this +context, \"trapping\" means to install handler code. + +The shell code `ARGUMENT` is to be read and executed whenever the shell +receives a signal or another event `SIGNAL`. The given `SIGNAL` +specification can be + +- the name of a signal with the SIG prefix, e.g. `SIGTERM` +- the name of a signal without the SIG prefix, e.g. `TERM` +- the number of a signal (see `trap -l`), e.g. `15` +- the name or number of a special event (see table below), e.g. `EXIT` + +Without any options or operands, `trap` prints a list of installed traps +in a reusable format (equivalent to the `-p` option). + +Special `ARGUMENT`s + +- if `ARGUMENT` is absent or `-` (dash), the signal/event handler is + reset to its original value +- if `ARGUMENT` is the null string, the signal/event is ignored + +Special events + + Name Code Description + ---------- ------ -------------------------------------------------------------------------------------------------------------------------------------------- + `EXIT` 0 executed on shell exit + `DEBUG` executed before every simple command + `RETURN` executed when a shell function or a sourced code finishes executing + `ERR` executed each time a command\'s failure would cause the shell to exit when the [`-e` option (`errexit`)](/commands/builtin/set) is enabled + +### Options + + Option Description + -------- ------------------------------------------------------------------------------------------ + `-l` print a list of signal names and their corresponding numbers + `-p` display the trap commands associated with each signal specification in a reusable format + +### Return status + + Status Reason + -------- ------------------------------ + 0 no error/success + !=0 invalid option + !=0 invalid signal specification + +## Examples + +### List installed traps + + trap + +### Ignore terminal interrupt (Ctrl-C, SIGINT) + + trap '' INT + +## Portability considerations + +- `trap` is specified by POSIX(R) without the `-l` and `-p` options +- in POSIX(R), beside signals, only `EXIT` (0) is valid as an event + +## See also + +- [the set command](/commands/builtin/set) for the `-e` (`errexit`) + option diff --git a/docs/commands/builtin/unset.md b/docs/commands/builtin/unset.md new file mode 100644 index 0000000..cda7424 --- /dev/null +++ b/docs/commands/builtin/unset.md @@ -0,0 +1,181 @@ +# The unset builtin command + +## Synopsis + + unset [-f|v] [-n] [NAME ...] + +## Description + +The `unset` builtin command is used to unset values and attributes of +shell variables and functions. Without any option, `unset` tries to +unset a variable first, then a function. + +### Options + + Option Description + -------- -------------------------------------------------------------------------------------------------------------- + `-f` treats each `NAME` as a function name + `-v` treats each `NAME` as a variable name + `-n` treats each `NAME` as a name reference and unsets the variable itself rather than the variable it references + +### Exit status + + Status Reason + -------- ---------------------------------------------------- + 0 no error + !=0 invalid option + !=0 invalid combination of options (`-v` **and** `-f`) + !=0 a given `NAME` is read-only + +## Examples + + unset -v EDITOR + + unset -f myfunc1 myfunc2 + +### Scope + +In bash, unset has some interesting properties due to its unique dynamic +scope. If a local variable is both declared and unset (by calling unset +on the local) from within the same function scope, then the variable +appears unset to that scope and all child scopes until either returning +from the function, or another local variable of the same name is +declared underneath where the original variable was unset. In other +words, the variable looks unset to everything until returning from the +function in which the variable was set (and unset), at which point +variables of the same name from higher scopes are uncovered and +accessible once again. + +If however unset is called from a child scope relative to where a local +variable has been set, then the variable of the same name in the +next-outermost scope becomes visible to its scope and all children - as +if the variable that was unset was never set to begin with. This +property allows looking upwards through the stack as variable names are +unset, so long as unset and the local it unsets aren\'t together in the +same scope level. + +Here\'s a demonstration of this behavior. + + #!/usr/bin/env bash + + FUNCNEST=10 + + # Direct recursion depth. + # Search up the stack for the first non-FUNCNAME[1] and count how deep we are. + callDepth() { + # Strip "main" off the end of FUNCNAME[@] if current function is named "main" and + # Bash added an extra "main" for non-interactive scripts. + if [[ main == !(!("${FUNCNAME[1]}")|!("${FUNCNAME[-1]}")) && $- != *i* ]]; then + local -a 'fnames=("${FUNCNAME[@]:1:${#FUNCNAME[@]}-2}")' + else + local -a 'fnames=("${FUNCNAME[@]:1}")' + fi + + if (( ! ${#fnames[@]} )); then + printf 0 + return + fi + + local n + while [[ $fnames == ${fnames[++n]} ]]; do + : + done + + printf -- $n + } + + # This function is the magic stack walker. + unset2() { + unset -v -- "$@" + } + + f() { + local a + if (( (a=$(callDepth)) <= 4 )); then + (( a == 1 )) && unset a + (( a == 2 )) && declare -g a='global scope yo' + f + else + trap 'declare -p a' DEBUG + unset2 a # declare -- a="5" + unset a a # declare -- a="4" + unset a # declare -- a="2" + unset a # ./unset-tests: line 44: declare: a: not found + : # declare -- a="global scope yo" + fi + } + + a='global scope' + f + + # vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et: + +output: + + declare -- a="5" + declare -- a="4" + declare -- a="2" + ./unset-tests: line 44: declare: a: not found + declare -- a="global scope yo" + +Some things to observe: + +- `unset2` is only really needed once. We remain 5 levels deep in + `f`\'s for the remaining `unset` calls, which peel away the outer + layers of `a`\'s. +- Notice that the \"a\" is unset using an ordinary unset command at + recursion depth 1, and subsequently calling unset reveals a again in + the global scope, which has since been modified in a lower scope + using declare -g. +- Declaring a global with declare -g bypasses all locals and sets or + modifies the variable of the global scope (outside of all + functions). It has no affect on the visibility of the global. +- This doesn\'t apply to individual array elements. If two local + arrays of the same name appear in different scopes, the entire array + of the inner scope needs to be unset before any elements of the + outer array become visible. This makes \"unset\" and \"unset2\" + identical for individual array elements, and for arrays as a whole, + unset and unset2 behave as they do for scalar variables. + +### Args + +Like several other Bash builtins that take parameter names, unset +expands its arguments. + + ~ $ ( a=({a..d}); unset 'a[2]'; declare -p a ) + declare -a a='([0]="a" [1]="b" [3]="d")' + +As usual in such cases, it\'s important to quote the args to avoid +accidental results such as globbing. + + ~ $ ( a=({a..d}) b=a c=d d=1; set -x; unset "${b}["{2..3}-c\]; declare -p a ) + + unset 'a[2-1]' 'a[3-1]' + + declare -p a + declare -a a='([0]="a" [3]="d")' + +Of course hard to follow indirection is still possible whenever +arithmetic is involved, also as shown above, even without extra +expansions. + +In Bash, the `unset` builtin only evaluates array subscripts if the +array itself is set. + + ~ $ ( unset -v 'a[$(echo a was set >&2)0]' ) + ~ $ ( a=(); unset -v 'a[$(echo a was set >&2)0]' ) + a was set + +## Portability considerations + +Quoting POSIX: + + If neither -f nor -v is specified, name refers to a variable; if a variable by that name does not exist, it is unspecified whether a function by that name, if any, shall be unset. + +Therefore, it is recommended to explicitly specify `-f` or `-v` when +using `unset`. Also, I prefer it as a matter of style. + +## See also + +- [declare](/commands/builtin/declare) +- [unset](/commands/builtin/unset) +- [POSIX `unset` + utility](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_29) diff --git a/docs/commands/builtin/wait.md b/docs/commands/builtin/wait.md new file mode 100644 index 0000000..78139b8 --- /dev/null +++ b/docs/commands/builtin/wait.md @@ -0,0 +1,44 @@ +# The wait builtin command + +## Synopsis + + wait [-f] [-n] [-p VARNAME] [ID...] + +## Description + +The `wait` builtin command is used to wait for job completion and return +exit status. + +- if `ID` is a job specification, it waits for all processes in the + pipeline of this job +- waits for a specific job (asynchronous command) and report its exit + status if one or more `ID` is given +- waits for all running jobs (asynchronous commands) +- waits for \"the next\" job (`-n` option) +- waits for termination instead of status change (`-f` option) + +`ID` may be an operating system process identifier or a shell job +specification. + +### Options + + Option Description + -------------- --------------------------------------------------------------------------------------------------------------------------------- + `-n` Waits for \"the next\" child to exit (as opposed to \"all children\" without this option). Accepts a list of IDs (jobs) + `-f` Waits for the termination of the given `ID` (instead of waiting for a status change only) + `-p VARNAME` When waiting for a list (-n) or all jobs, writes the job ID to the job that was actually terminated into the variable `VARNAME` + +### Return status + +The return status is the return status of the job waited for, or + + Status Reason + -------- ------------------------------------------------- + 0 waited for all jobs in shell\'s job list + 1 the given `ID` is not a valid job or process ID + +## Examples + +## Portability considerations + +## See also