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 ofsleep
tells Bash that it was interrupted by the SIGINT signal andbash
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 oncesleep
has ended.
Related Topics
Changing Color of Eclipse Links in Quick Fix or Eclipse Links in Preferences on Linux
Installing Multiple Versions of R
Bash Script: Always Show Menu After Loop Execution
Bluetooth Error: Native Library Bluecove_Arm Not Available
Ignore Case When Trying to Match File Names Using Find Command in Linux
Why Exported Variables in Makefile Is Not Received by Executable
How to Kill a Process on No Output for Some Period of Time
How Does the Linux Kernel Determine Ld.So's Load Address
Lazarus: How to List All the Available Network Connection on a System
Redirect Two or More Stdout to a Single Stdin
Why Do We Need to Call Poll_Wait in Poll
How to Tell If Running in a Linux Console Versus an Ssh Session
Switching Users Using Winscp Between Different Accounts
Loading Executable or Executing a Library
How to Get Environment Variables of Remote Host
Cmake Set Environment Variable