How to repeat request after returning trap in bash?

I have a script that should catch SIGTERM and SIGTSTP. This is what I have in the main block:

trap 'killHandling' TERM 

And in function:

 killHandling () { echo received kill signal, ignoring return } 

... and similar for SIGINT. The problem is the user interface. The script asks the user for some input, and if SIGTERM or SIGINT occurs when the script is waiting for input, it is confusing. Here is the result in this case:

 Enter something: # SIGTERM received received kill signal, ignoring # shell waits at blank line for user input, user gets confused # user hits "return", which then gets read as blank input from the user # bad things happen because of the blank input 

I definitely saw scripts that handle this more elegantly, for example:

 Enter something: # SIGTERM received received kill signal, ignoring Enter something: # re-prompts user for user input, user is not confused 

What is the mechanism used to execute the latter? Unfortunately, I cannot just change my trap code to execute a second prompt, as the script offers the user a few things and what the hint says depends on the context. And there has to be a better way than writing context-sensitive trap functions.

I would really appreciate any pointers. Thanks!

+4
source share
2 answers

CodeGnome's answer gave work, but as he points out, it is not reliable; second control-c causes unwanted behavior. I ended up encountering a problem by improving the use of existing input validation in code. So my interrupt handling code now looks like this:

 killHandling () { echo received kill signal, ignoring echo "<<Enter>> to continue" return } 

Now the cursor is still waiting for an empty string for user input, but the user is not confused and presses the Enter key as requested. Then, the input confirmation script detects that an empty string has been entered, which is considered as invalid input, and the user is prompted to enter something.

I remain grateful to CodeGnome for his suggestions, from which I learned a couple of things. And I apologize for the delay in posting this answer.

0
source

These are not very reliable methods - there are some problems with the way it treats CTRL-C as a character after the first trap, for example, but they both handle the use case you use.

Use BASH_COMMAND to re-run the last command (e.g. read).

 prompt () { read -p 'Prompting: ' } reprompt () { echo >&2 eval "$BASH_COMMAND" } trap "reprompt" INT prompt 

In this case * BASH_COMMAND * evaluates to read -p 'Prompting: ' . Then the command should be reworked using eval. If you do not rate this, you may run into strange quoting problems. YMMV.

Use FUNCNAME to re-run the previous function in the call stack.

 prompt () { read -p 'Prompting: ' } reprompt () { echo >&2 "${FUNCNAME[1]}" } trap "reprompt" INT prompt 

In this example, FUNCNAME [1] expands to prompt , which is the previous function on the stack. We simply call it recursively, as many times as necessary.

+2
source

All Articles