How to trap CTRL+Z in Linux POSIX shell script; possible or not?
To ignore Ctrl+Z typed from a terminal, you can do:
trap '' TSTP
# or possibly equivalently
trap '' 18
trap '' 20
trap '' 24
As noted by others, there are other signals that cannot be blocked, such as SIGKILL and SIGSTOP.
Many shells map Ctrl+\ to SIGKILL and Ctrl+C to SIGINT.
stty -a
should show settings for sending "susp" (SIGTSTP), "intr" (SIGINT) and "quit" (SIGKILL). These keystrokes can be rebound by the user if desired.
Editor's notes:
You cannot use
SIGTSTP
pseudonym in a POSIX shell script.Even if you know for sure what exact signal number your terminal sends, if writing a script for general use, you ought to block all those three possibilities.
ShellCheck warning, and I quote:
Trapping signals by number is not well defined. Prefer signal names. [SC2172]
Means these signal numbers can vary between platforms, try 15 for SIGTERM and you will see no warning at all as that one is POSIX standardized. Ergo, you might want to disable these after you've tested your code with:
# shellcheck disable=SC2172
Link to wiki: https://github.com/koalaman/shellcheck/wiki/SC2172
How to trap input to control the screenshot function?
As an alternative to using readline on a shell prompt, consider the following bash solution. Solution closely matching requirements. Basically:
Loop Forever:
- Wait for Ctrl/A
- Start screenshot in backgroun
- Wait for Ctrl/B
- Stop screen shot, Run external screenshot.sh
It uses bash to read one-character at a time line delimiter is needed.
Side note: Given program running in a window with dedicated terminal, the Ctrl/A and Ctrl/B can be replaced with something easier - just 'A' and 'B'.
#! /bin/bash
screenshot(){
rm -f /tmp/out.mp4
exec ffmpeg -video_size 1920x1080 -framerate 25 -f x11grab -i :0.0+0,0 /tmp/out.mp4
}
while true ; do
a=""
echo "Type CTRL/A to start"
while [ "$a" != $'\x01' ] ; do
read -N1 a
done
screenshot &
sleep 3
echo
echo "Type CTRL/B to start"
while [ "$a" != $'\x02' ] ; do
read -N1 a
done
echo "Processing ..."
kill $!
bash myscreenshot.sh &
done
how can the bash script kill self if it received ctrl z
Just force an exit when the Python call fails:
python xxx.py || exit 1
You could use break
instead of exit
to just leave the loop. More advanced error handling can be achieved by evaluating $?
; here's an example how to store the return value and reuse it:
python xxx.py
result=$?
if [ ${result} -ne 0 ]; then
# Error
echo "xxx.py exited with ${result}"
...
else
# Success
...
fi
As a general rule, not only regarding Bash scripting but programming in general, always check return codes of commands for errors and handle them. It makes debugging and your working life in general easier in the long run.
Trap signals both in script and subshells
There is no easy way to propagate the particular signal from child to parent.
However, exit code is 130 if the program is terminated by Ctrl-C in many cases. fzf
follows it also.
Checking exit status and sending signal to own process is one of the workaround.
#!/bin/sh
trap 'echo "exiting.."; exit 0;' INT
var1=$(echo "ab\nab" | fzf)
[ $? -eq 130 ] && kill -INT $$
var2=$(echo "cd\ncd" | fzf)
[ $? -eq 130 ] && kill -INT $$
However, it is not common way.
If it needs to do something when terminated with any errors, using set -e
and trapping EXIT
or other signals is general way.
#!/bin/sh
set -e
trap 'echo "exiting.."; exit 0;' EXIT
var1=$(echo "ab\nab" | fzf)
var2=$(echo "cd\ncd" | fzf)
bash trap will echo from keyboard Ctrl-C while not kill 2
With kill -s SIGINT 50138
, you are only sending the signal to the shell's process, and that has to wait for sleep 1000
to finish, because sleep
doesn't receive the signal.
Control-C, though, causes the terminal to send SIGINT
to every process in the current process group, so both your shell script and sleep
receive it. Your script still doesn't process the trap command until sleep
completes, but sleep
exits immediately in response to the SIGINT
it just received from the terminal.
If your kill
supports it, you can also use kill -s SIGINT -50138
(note the negative process id) to send SIGINT to the entire process group.
Can successfully trap CTRL-Z, but not SIGTSTP
First you must not trap SIGTSTP for the shell itself (it should ignore it), only for its child. Second if you really want to write a job controller shell, you need to manage children with the help of process group and correctly set the foreground group. Writing a shell that behave correctly with job control is a heavy task. Read POSIX standard about shells, groups, sessions, terminal control.
About your current problem. If your sub process does an exec then each handled signal is reset to its default behavior. This is because exec recovers the old code with the new one, so the previously set handler is no more available. Now you must let the child behave normally against TSTP
and just let the parent track its status either with a synchronous call to wait/waitpid
or with the asynchronous help of SIGCHLD
. When the child stops or terminates, the parent is able to see it in the returned status (WIFEXITED
, WIFSIGNALED
, WIFSTOPPED
).
Related Topics
Embed Icc Color Profile in PDF
Does Cron Expression in Unix/Linux Allow Specifying Exact Start and End Dates
Linux Kernel - Add System Call Dynamically Through Module
Cpu Affinity Masks (Putting Threads on Different Cpus)
Telnet to Login with Username and Password to Mail Server
How to Start Redis-Server on a Different Port Than the Default Port 6379 in Ubuntu
Overlay Two Postscript Files (Command Line Approach)
Run Shell Script When Saving a File in Sublime Text 3
Convert a Text File into Columns
Return Code When Os Kills Your Process
How Is the Address of the Text Section of a Pie Executable Determined in Linux
Does Linking an '-Lpthread' Changes Application Behaviour? (Linux, Glibc)
Add a Header to a Tab Delimited File
Building a Simple (Hello-World-Esque) Example of Using Ld's Option -Rpath with $Origin
Binary Data Over Serial Terminal
Get Rid of "Gcc - /Usr/Bin/Ld: Warning Lib Not Found"
How to Use Kgdb Over Ethernet (Kgdboe)
Printing Current Time in Milliseconds or Nanoseconds with Printf Builtin