Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In bash, which traps are inherited by functions and builtins?

I'm not really clear on which traps are inherited when in bash. The manpage says:

When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment [...] [T]raps caught by the shell are reset to the values inherited from the shell's parent, and traps ignored by the shell are ignored[.]

Later on it says that subshells behave the same way.

This makes enough sense to me, I think. It sounds like if a shell unsets a trap, that gets remembered by any subshells and whatnot, while if a shell sets a trap, that gets forgotten. I don't get why that design choice was made, but I at least think I understand what's going on.

But what about commands that are builtins or shell functions? And do the two ever behave differently (with respect to trap inheritance)? I can't find a comprehensive description in the manual--as far as I can tell, anything goes. It seems like they are usually inherited from the parent, but there are exceptions like ERR and RETURN, each of which are only inherited by functions when certain shell options are being used.

My questions are:

  • What exactly is the typical way trap inheritance works for builtins and functions? E.g., are there any subtleties regarding setting vs. unsetting traps, the way there appears to be with most commands?

  • Do all functions and builtins behave the same way? (Please don't tell me each builtin has a separate set of rules...)

  • What are the exceptions? I.e., what signals behave differently by default, and what functions can have their default behavior changed by shell options and whatnot? I know about ERR and RETURN, but are there any others? Try as I might, I couldn't find a nice simple list of this anywhere.

  • When, if ever, can a function or builtin affect the traps of a parent? How does trap - SIGSPEC vs. trap '' SIGSPEC play into this?

Thanks!

PS: I am using GNU bash version "4.4.19(1)-release".

like image 254
greatBigDot Avatar asked Apr 09 '18 01:04

greatBigDot


1 Answers

The original post contain multiple questions. Trying to address the last question: When, if ever, can a function or builtin affect the traps of a parent? How does trap - SIGSPEC vs. trap '' SIGSPEC play into this? (2 questions)

When can a function affect traps of a parent ?

Short Answer: Only functions running in the same process as the parent caller can impact the caller.

Long Answer: It is important to note that signals are specific to 'execution environment'. In linux/Unix this is a process. The inheritance happens between processes. Therefore a function can impact the 'parent' (the caller) only if executed in the same process. It will not be able to impact the 'parent' if executed in a different process. Examples for using a sub-shell are the when a sub-shell is forced (using '(command)'), when using a pipeline (with the exception of the last command of the pipeline), when using command substitutions, and more.

function f {
   trap 'echo SIGNAL' TERM
}

# Will impact current process traps, as 'f' is executed in the same process
f
# Will not impact current process traps, as 'f' is executed in a sub-shell.
(f)

Difference between 'trap - SIG' and 'trap "" sig':

Short Answer: The '-' will restore signal behavior, "" will ignore it. For most signals, the default behavior is to terminate the shell.

Long Answer: Using 'trap - SIG' will reset the signal to the default behavior, whereas 'trap "" SIG' will force the signal to be ignored.

For (few) signals the default (initial) behavior is to be ignored (e.g. QUIT), therefore, there is no difference between the commands. For most other signals (e.g., QUIT), the default behavior is to ignore the signal. You can use 'trap "" SIG' to prevent the signal from having impact during specific point of time.

For example: Disallow ctrl/C (INTR) during copying of critical files:

sleep 5
# Disable INT during copying of critical files
trap '' INT
cp -r critical-file backup
# Restore INT behavior
trap -- INT

Since signals are inherited, the 'default' behavior of a signal can be modified. Consider:

# Get greeting on USR1
trap 'echo HI' USR1
# Start sub-shell
(
# USR1 will result in 'HI'
sleep 5
trap '' USR1
# USR1 will be ignored during critical file copy
cp -r critical-file backup
# Restore INT behavior
trap - INT
# USR1 will result in 'HI'
sleep 5
)
like image 69
dash-o Avatar answered Sep 20 '22 05:09

dash-o