Sending Sigint from Keyboard to Piped Commands in Bash

Sending SIGINT from keyboard to piped commands in bash

In short, they all do.

When setting up a pipeline, the shell creates a process group. ^C is interpreted by the kernel's line discipline as the user's request to interrupt the process group currently running in the foreground. Sending a signal such as SIGINT to a process group automatically delivers the signal to all processes in the group.

Which signal does ctrl-x send when used in a terminal?

To get all the terminal control character assignments:

stty -a

How can I catch SIGINT without closing xterm?

When you send SIGINT to bash script the signal is propagate to current process in the script, then it executes command in trap. So "wait" is interrupted. You must do that "wait" run again.

Also you must do that all jobs are launched in their own process groups (set -m). From the set man page:

set -m

Monitor mode. Job control is enabled. This option is on by default for interactive shells on systems that support it (see JOB
CONTROL above). Background processes run in a
separate process group and a line containing their exit status is printed upon their completion.

#!/bin/bash
set -m
trap 'R=true' SIGINT
xterm &
while : ; do
R=false
wait
[[ $R == true ]] || break
done

You can see commands that it run with '-x' option in shebang.

Stopping a unix program using keyboard, during redirected input, without SIGINT, in C

If you want an interactive TTY user to be able to stop a program using an input character (not a signaling character which causes the TTY driver to deliver a signal), and that program must be redirected, then your only resort is to explicitly open a file descriptor to the TTY device (via /dev/tty) and monitor that for input.

Your kbhit function should probably take an int fd parameter, using which you give it the open TTY file descriptor that it should poll.

If you want a single character input from a TTY to be immediately available to the program (even if that character isn't a newline), then you have to put the TTY into "raw mode", or at least partially: at the very least, you have to disable "canonical input processing" via negating the ICANON flag in the c_iflag numeric field in the struct termios structure, and ensure that c_cc[VTIME] and c_cc[VMIN] are set to 0 and 1, respectively. Look up tcgetattr and tcsetattr. You probably want to disable the signaling characters, and disable echoing and other things. Some platforms have a cfmakeraw function which tweaks a struct termios object in the right ways to bring about a very raw mode without having to fiddle with any of the termios flags.

In canonical input processing mode, a TTY won't make input available to the process (and won't select positive under select for input) until a complete line of input is received.

What's the best way to send a signal to all members of a process group?

You don't say if the tree you want to kill is a single process group. (This is often the case if the tree is the result of forking from a server start or a shell command line.) You can discover process groups using GNU ps as follows:

 ps x -o  "%p %r %y %x %c "

If it is a process group you want to kill, just use the kill(1) command but instead of giving it a process number, give it the negation of the group number. For example to kill every process in group 5112, use kill -TERM -- -5112.

Prevent CTRL+C being sent to process called from a Bash script

I ended up using a modified version of what @thatotherguy suggested:

#!/bin/bash

term() {
echo ctrl c pressed!
# perform cleanup - don't exit immediately
}
trap term SIGINT

sleep 100 &
pid=$!

while ps -p $pid > /dev/null; do
wait $pid
done

This checks if the process is still running and, if so, runs wait again.

Handling signals in bash script when it started as a background process

Bash manual states:

  • Background processes (...) are immune to keyboard-generated signals.
  • If bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

Consequently:

  • If your script runs in the foreground: when you press "Ctrl-C", a SIGINT is sent to the currently running process (i.e. the sleep command). The exit status of sleep tells Bash that it was interrupted by the SIGINT signal and bash calls your trap.
  • If your script runs in the background, then the backgrounded sleep does not receive the signal and the SIGINT trap is only executed once sleep has ended.


Related Topics



Leave a reply



Submit