Trap: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
No edit summary
Line 10: Line 10:
=Overview=
=Overview=


"trap" statement is a bash facility that allows for code execution upon catching specific signals. This is very useful in scripts when cleanup code needs to be executed upon the script exit, in a manner similar to the "finally" Java facility.
"trap" statement is a bash facility that allows for code execution upon catching specific signals. A common usage in shell scripts is to prevent a script to exit untimely when the user types a keyboard abort sequences, but run cleanup code instead. Conceptually, the trap facility is similar to the Java "finally" construct.
 


=Syntax=
=Syntax=
Line 17: Line 18:
trap <commands> <signals>
trap <commands> <signals>
</syntaxhighlight>
</syntaxhighlight>
One or more signals can be listed. The signals can be listed with or without "SIG" prefix (




Line 41: Line 44:




Trap is a facility to instruct bash to catch signals and execute code depending on the signal. A common usage in shell scripts is to prevent those scripts to exit untimely when users type keyboard abort sequences, but run cleanup code instead.


Example:
Example:

Revision as of 22:00, 23 July 2020

External

Internal

Overview

"trap" statement is a bash facility that allows for code execution upon catching specific signals. A common usage in shell scripts is to prevent a script to exit untimely when the user types a keyboard abort sequences, but run cleanup code instead. Conceptually, the trap facility is similar to the Java "finally" construct.


Syntax

trap <commands> <signals>

One or more signals can be listed. The signals can be listed with or without "SIG" prefix (














Example:

trap 'rm -f ./lock' EXIT

Global variables declared before the trap declaration are correctly resolved when present in a single-quote quoted string (even if single-quotes are used, the single quote semantics when used in bash command line is different from that in effect here). For example, the following code:

a=hello
trap 'echo ${a}' EXIT

produces:

hello

Variable resolution is done at the time of execution, not declaration, so the following:

trap 'echo ${a}' EXIT
a=hello

also produces:

hello

Experiment with local variables. This works, explain this:

local chart_dir=blah
trap 'rm -rf '${chart_dir}'/tmpcharts; echo chart dir: ${chart_dir}' EXIT

produces:

chart dir: blah

This seems to work for local variables:

 trap 'rm -rf '${tmp_dir}' && debug '${tmp_dir}' removed; rm -rf '${chart_dir}'/tmpcharts && debug '${chart_dir}'/tmpcharts removed' EXIT

Special Bash Signals

"EXIT" in the example above is not a Linux signal. Bash provides this psuedo-signal, which is executed when the script exits; this can be used to make sure that your script executes some cleanup on exit.

Other bash pseudo-signals:

  • DEBUG
  • RETURN
  • ERR

For a list of signals that can be handled, see:

Linux Signals

Also see:

Handling Signals in bash

Only One Code Sequence (Latests) Executes

If multiple code sequences are declared with trap, only the last one is executed. The following example:

trap 'echo A' EXIT
trap 'echo B' EXIT

produces:

B

Behavior on Being Invoked from Sub-Shells

If code is registered with trap to react to EXIT in a sub-shell, or in a function that is invoked in a sub-shell, then the registered code will be executed when the sub-shell, and not the top-level invoking shell, exists.

The following code:

$(trap 'echo "a" 1>&2' EXIT)
echo "b"

will display:

a
b

Note that the output should be sent to stderr in the trap code - if the output is sent to stdout, the output is lost, even if the code executes.

Example

Delete Temporary Directory on Exit

local tmp_dir
local preserve_tmp_dir=false
tmp_dir=$(get-tmp-dir) || exit 1
if ${preserve_tmp_dir}; then
    debug "temporary directory ${tmp_dir} will be preserved on exit"
else
    trap "rm -rf ${tmp_dir} && debug deleted temporary directory ${tmp_dir} || warn failed to delete temporary directory ${tmp_dir}" EXIT && \
    debug "registered temporary directory ${tmp_dir} cleanup procedure"
fi

TODO

Reactive Wait Container

Investigate usefulness in case of a reactive wait container. Also see Docker Concepts - Container Exit.

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

Other Usage Patterns

trap "rm -f /tmp/blah" 0 2 3 5 10 13 15

Wrap the whole trap functionality in a function

trap _trap SIGTERM

function _trap() {
 ...
}