How to close a dd process that was started in a dash script with -SIGINT? - linux

When I start a dd process directly from the Terminal with
dd if=/dev/zero of=/dev/null &
command, and send to it a -SIGINT with
kill -SIGINT <pid>
command, it closes successfully.
But when I start the process from a script
#!/bin/sh
dd if=/dev/zero of=/dev/null &
Then do
kill -SIGINT <pid>
it doesn't affect the process.
I wonder why this is so.
I didn't find any related information on the internet.

POSIX says:
If job control is disabled (see the description of set -m) when the shell executes an asynchronous list, the commands in the list shall inherit from the shell a signal action of ignored (SIG_IGN) for the SIGINT and SIGQUIT signals.
This is likely because Ctrl+C sends a sigint to every process in the group, so without this behavior, any backgrounded processes would unexpectedly be killed when you try to interrupt the main script.

Related

How to catch SIGINT within a Bash subshell

If I run a command, such as grep, at the command line and hit ^C, the command is properly killed (with SIGINT I think). And if I run the grep in background and then run a kill SIGINT on its PID, it similarly gets terminated. But if I'm inside a script and run grep in background from the script, get its PID and then use 'kill -s SIGINT $PID', grep does not get killed. Why? If I use SIGTERM, instead of SIGINT, the kill does work.
#!/bin/bash
grep -rqa shazam /usr &
PID=$!
kill -s SIGINT $PID
Even if I put the grep in a subprocess, preceded by a SIGINT handler (in the subprocess), and hit the subprocess with SIGINT, the handler is not invoked.
#!/bin/bash
( trap 'echo "caught signal"' SIGINT; grep -rqa shazam /usr ) &
PID=$!
kill -s SIGINT $PID
The trap handler is invoked if I use SIGTERM, instead of SIGINT, but does not interrupt grep. If I add '/bin/kill -s SIGTERM 0' to the trap handler, there is an indication that the grep process gets terminated, but grep has already completed its work by then. I realize that Bash may have different default behaviors for the different signals, but I don't understand why my call to kill SIGINT is different than a ^C, why the trap call works for SIGTERM, but not for SIGINT, nor why SIGTERM isn't handled by the subprocess immediately.
Well, with further digging, I figured out 2 of my 3 questions. When I backgrounded grep within the script, the shell told it to ignore SIGINT. And Bash says it will wait to handle the signal until the subcommand is complete in some situations (which I don't fully follow at the moment), but the signal is handled immediately if hit the grep process directly with pkill.
"Actually bash will disable SIGINT (and SIGQUIT) on background processes and they can't be enabled" Background process and signals How SIGINT works
"Further background jobs are not supposed to be tied to the shell that started them. If you exit a shell, they will continue running. As such they shouldn't be interrupted by SIGINT, not by default. When job control is enabled, that is fulfilled automatically, since background jobs are running in separate process groups. When job control is disabled (generally in non-interactive shells), bash makes the asynchronous commands ignore SIGINT." Independent Program
Reason why SIGTERM works

How to kill a process by its pid in linux

I'm new in linux and I'm building a program that receives the name of a process, gets its PID (i have no problem with that part) and then pass the PID to the kill command but its not working. It goes something like this:
read -p "Process to kill: " proceso
proid= pidof $proceso
echo "$proid"
kill $proid
Can someone tell me why it isn't killing it ? I know that there are some other ways to do it, even with the PID, but none of them seems to work for me. I believe it's some kind of problem with the Bash language (which I just started learning).
Instead of this:
proid= pidof $proceso
You probably meant this:
proid=$(pidof $proceso)
Even so,
the program might not get killed.
By default, kill PID sends the TERM signal to the specified process,
giving it a chance to shut down in an orderly manner,
for example clean up resources it's using.
The strongest signal to send a process to kill without graceful cleanup is KILL, using kill -KILL PID or kill -9 PID.
I believe it's some kind of problem with the bash language (which I just started learning).
The original line you posted, proid= pidof $proceso should raise an error,
and Bash would print an error message about it.
Debugging problems starts by reading and understanding the error messages the software is trying to tell you.
kill expects you to tell it **how to kill*, so there must be 64 different ways to kill your process :) They have names and numbers. The most lethal is -9. Some interesting ones include:
SIGKILL - The SIGKILL (also -9) signal forces the process to stop executing immediately. The program cannot ignore this signal. This process does not get to clean-up either.
SIGHUP - The SIGHUP signal disconnects a process from the parent process. This an also be used to restart processes. For example, "killall -SIGUP compiz" will restart Compiz. This is useful for daemons with memory leaks.
SIGINT - This signal is the same as pressing ctrl-c. On some systems, "delete" + "break" sends the same signal to the process. The process is interrupted and stopped. However, the process can ignore this signal.
SIGQUIT - This is like SIGINT with the ability to make the process produce a core dump.
use the following command to display the port and PID of the process:
sudo netstat -plten
AND THEN
kill -9 PID
Here is an example to kill a process running on port 8283 and has PID=25334
You have to send the SIGKILL flag with the kill statement.
kill -9 [pid]
If you don't the operating system will choose to kill the process at its convenience, SIGKILL (-9) will tell the os to kill the process NOW without ignoring the command until later.
Try this
kill -9
It will kill any process with PID given in brackets
Try "kill -9 $proid" or "kill -SIGKILL $proid" commands. If you want more information, click.
Based on what you have there, it looks like you aren't getting the actual PID in your proid variable. If you want to capture the output of pidof, you will need to enclose that command in backtics for the old form of command substitution ...
proid=`pidof $proceso`
... or like so for the new form of command substitution.
proid=$(pidof $proceso)
I had a similar problem, only wanting to run monitor (Video surveillance) for several hours a day.
Wrote two sh scripts;
cat startmotion.sh
#!/bin/sh
motion -c /home/username/.config/motion/motion.conf
And the second;
cat killmotion.sh
#!/bin/sh
OA=$(cat /var/run/motion/motion.pid)
kill -9 $OA
These were called from crontab at the scheduled time
ctontab -e
0 15 * * * /home/username/startmotion.sh
0 17 * * * /home/username/killmotion.sh
Very simple, but that's all I needed.

Bash script dd and fsck not killed

I need to remove a lv which is under use from a script which is doing a dd, fcsk and some more tasks on some peer node.so am just killing the script and trying to remove the lv from that peer, but it seems not working with error open lvs.
but for the same case if i kill the dd then removing the lv its working fine.
may be am asking a silly question but need to know why so??
If you kill your script sending SIGTERM or SIGKILL to its PID, normally you would send the signal only to the parent process. dd is running in a child process which won't receive the signal. Once the parent is killed, the child is inherited by init and it will keep on running.
To send the signal to the whole process group use:
kill -- -PID
or
kill -9 -PID
where PID is the PID of your script. Note the minus sign prepended to PID.
From man kill
-n where n is larger than 1. All processes in process group n are signaled.
Example
I am running dd from a shell script:
PID TGID TID PGID PPID COMMAND
5828 5828 5828 5828 20127 sh
5829 5829 5829 5828 5828 dd
The Process Group ID (PGID) is the PID of the parent (5828).
If I run the following command:
kill -9 5828
I obtain the following situation:
PID TGID TID PGID PPID COMMAND
5829 5829 5829 5828 1 dd
dd is still running and it has been inherited by init (PPID is 1).
If instead I run:
kill -9 -5828
both the script and dd are killed.
EDIT: The process you want to kill is launched remotely via ssh.
Having ssh launch dd/fsck remotely changes everything. A simple but not recommended solution could be the following.
A script launches dd/fsck remotely via ssh in the background and gets the PID.
remote_pid=$(ssh user#host 'dd if=/dev/urandom of=/dev/zero & echo $!')
Then the script must not return and trap your signal. Your handler opens a new ssh connection and signals remote_pid.
Cleaning up in a second ssh connection is not recommended, as it could fail and leave a lot of mess behind.
For a more advanced solution please see https://unix.stackexchange.com/questions/40023/get-ssh-to-forward-signals

Spawn parallel processes in foreground

using bash in linux is it possible to spawn parallel processes in the foreground? For example the following :
top.sh
#!/bin/bash
./myscript1.sh &
./myscript2.sh &
will spawn two processes in parallel as background threads. However is it possible to spawn these as foreground threads? The aim is to automatically kill myscript1.sh and myscript2.sh, when top.sh is killed. Thanks
You can only have one job in the foreground. You can make your script react to any signal that reaches it and forward the signal to other jobs. You need to make sure your script sticks around, if you want to have a central way of killing the subprocesses: call wait so that your script will not exit until all the jobs have died or the script itself is killed.
#!/bin/bash
jobs=
trap 'kill -HUP $jobs' INT TERM HUP
myscript1.sh & jobs="$jobs $!"
myscript2.sh & jobs="$jobs $!"
wait
You can still kill only the wrapper script by sending it a signal that it doesn't catch, such as SIGQUIT (which I purposefully left out) or SIGKILL (which can't be caught).
There's a way to have all the processes in the foreground: connect them through pipes. Ignore SIGPIPE so that the death of a process doesn't kill the previous one. Save and restore stdin and stdout through other file descriptors if you need them. This way the script and the background tasks will be in the same process group, so pressing Ctrl+C will kill both the wrapper script and the subprocesses. If you kill the wrapper script directly, that won't affect the subprocesses; you can kill the process group instead by passing the negative of the PID of the wrapper script (e.g. kill -TERM -1234).
trap '' PIPE
{
myscript1.sh <&3 >&4 |
myscript2.sh <&3 >&4
} 3<&0 4>&1
Using GNU Parallel your script would be:
#!/bin/bash
parallel ::: ./myscript1.sh ./myscript2.sh
Or even:
#!/usr/bin/parallel --shebang -r
./myscript1.sh
./myscript2.sh
Watch the intro videos to learn more: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

syncing a shell script with kernel operations

For stopping activity in my embedded Linux system, I have the following shell script (interpreted by busybox):
#!/bin/sh
pkill usefulp_program
swapoff /home/.swapfile
umount -l /home
sleep 3 # While I can't find a way to sync, sleep
If I take off the sleep line, the script returns immediately, without waiting even for the umount (which is lazy, as for some reason it refuses to unmount otherwise). Do you know how can I wait for all the three operations to complete before finishing the script? Resorting to an arbitrary sleep does not look like a good solution.
Also, any hint on why I can not umount without the -l?
You need to wait for the killed process to terminate. As per your comment...
wait <pid>
...doesn't work! So, could loop ala:
while ps -p <pid> > /dev/null; do sleep 1; done
to wait for the killed process to terminate before doing the swapoff and umount.
As others already mentioned you should and only the -l when the process is terminated. An option if it takes long/it just ignores you polite request to stop itself is using a different signal. The option would be -9 to the kill/killall/pkill command to send the SIGKILL instead of SIGTERM. If you dont want to use the hammer on your first try you could do something like
pkill your_programm
sleep 10
pkill -9 your_programm

Resources