How to kill a program by the hard way, only if it refuses to terminate the soft way? - linux

How to exit a program by bash on a soft way and if this was not successful do it on a hard way.
Its known how to open a programm by bash and how to get the PID of the programm. The follow sample open the editor XED:
xed & PID=$!
Its known how to echo the PID of the program what was opened:
echo $PID
12345 # sample output of a PID
Its known how to try to close a program on a soft way and how to select the program by PID for this:
kill -15 $PID # select a program by PID and tray to kill it on a soft way
Its known how to close a program on a hard way and how to select the program by PID for this:
kill -9 $PID # select a program by PID and kill it on a hard way
Put all together what I have, a still missing something:
xed & PID=$! # open the program xed and get the pid
echo PID of programm: $PID
sleep 5 # lets run the xed 5 seconds
kill -15 $PID # select the xed by PID and try to kill it on soft way
# check based on variant 1, 2, 3 or other, the xed was sucessfull killed on soft way or not
# if the xed still running, kill it on follow way
kill -9 $PID # select the xed by PID and kill it on hard way

Based one Answer of Eddy763, the follow Logically better fitting variant:
xed & PID=$! # Start XED and get PID
sleep 2
# kill -15 $PID # Soft Kill, activate or deactivate for testing
echo
echo
sleep 2
if ! ps -p $PID
then
echo "The PID/program are closed successful by Soft Kill"
else
echo "The PID/program didn't be killed successful by Soft Kill active, so it will be killed now on hard way"
kill -9 $PID # Hard Kill
fi
echo
echo

You can get the information about the process still running on follow way:
xed & xedPid=$! # Start of editor XED and asking for PID
[1] 12345
kill -15 $PID
# getting the follow, if the XED was killed successfull soft before:
kill -15 $PID
bash: kill: (12345) - Kein passender Prozess gefunden
**[1]+ Beendet xed**

You can get the information about the process are still running or not, on follow way too:
xed & xedPid=$! # Start of editor XED and asking for PID
[1] 12345
# Output if xed are running
kill -0 $PID
kill: Aufruf: kill [-s Signalname | -n Signalnummer | -Signalname] pid | jobspec ... oder kill -l [Signalname]
kill -15 $PID
# Output if XED are not more running:
kill -0 $PID
kill: Aufruf: kill [-s Signalname | -n Signalnummer | -Signalname] pid | jobspec ... oder kill -l [Signalname]
**[1]+ Beendet xed**

kill -15 $PID
sleep 1
if ps -p $PID > /dev/null
then
kill -9 $PID
fi

#!/bin/bash
xed & PID=$! # Start XED and get PID
sleep 3
# kill -15 $PID # Soft Kill, activate or deactivate for testing
echo
echo
sleep 3
if ps -p $PID
then
echo "The PID/program didn't be killed successful by Soft Kill"
kill -9 $PID # Hard Kill
else
echo "PID/program are already closed by Soft Kill"
fi
echo
echo

Related

How to check if a daemon successfully started as part of a script?

Let's say I have this script:
start daemon1 &
start daemon2 &
echo "Running..."
daemon2 can only be started if daemon1 was started successfully.
if daemon1 did not start successfully, then the script most be aborted
"Running..." should be displayed only if daemon2 started successfully.
if daemon2 did not start successfully, then the script most be aborted
How can I make this with a shell script ?
You can check the PID of the started process to see if it is running
start daemon1 &
P=$!
if kill -0 $P > /dev/null 2>&1 ; then
start daemon2 &
P=$!
if kill -0 $P > /dev/null 2>&1 ; then
echo "Running..."
fi
fi
Untested code. Comment if something is not right
I propose you capture the daemon's pid (process id) and then determine if the pid exists (after some delay in case daemon1 takes a while to process to start and crash). So here is a way of achieving that (in Linux, I'm ignoring the 'start' in your commands since I'm not familiar with the windows cmdline environment ):
start daemon1 &
pid1=$!
sleep 3 # give daemon1 some time to get going
if
kill -0 $pid1 2>/dev/null
then
start daemon2 &
pid2=$!
sleep 3 # give daemon2 some time to get going
if
kill -0 $pid2 2>/dev/null
then
echo "Running..."
fi
fi
The necessary ingredients for this recipe are:
$! returns the child's pid (of the last background process run)
kill -0 <pid> is a way of determining if a pid is valid (in the process table)

Kill -2 or Kill -INT ,how does it kill process

I have two shellscripts:
a.sh is:
#!/bin/bash
read -p "Enter name": name
echo $name
b.sh is:
#!/bin/bash
for ((i=0; i<100; i++))
do
echo "$i"
sleep 1s
done
then, I start another shell using command pkill -2 a.sh pkill -2 b.sh
but, the first can be killed
the second cannot be killed,
what does pkill -2 do?
Kill -2 sends an interrupt (2 is the value associated with SIGINT). This will wake up the sleep call but then the loop continues. If you send a 15 (SIGTERM), the process should terminate.

linux kill command -9 vs -15

I have a process that i would like to kill and then restart a service. Someone has written a code to kill the process by writing the following set of scripts
ps -ef |grep "process_name" | awk '{print "kill -15 " $2}'> /projects/test/kill.sh
#run the kill script
/projects/test/kill.sh
and then again
ps -ef |grep "process_name" | awk '{print "kill -9 " $2}'> /projects/test/kill.sh
#run the kill script
/projects/test/kill.sh
#finally
service restart command here
# the problem here is that service does not restart properly sometimes,
as it thinks that process is still running.
As i understand kill -15 gracefully kills the process. But then right away they have the kill -9 as well.
So if a process was getting killed in the first command, what happens when kill -9 is also run on the same process? Or will the ps -ef even list out that process since it has been marked for kill?
Thanks!
You are correct that kill -15 is to gracefully kill a process. But, killing a process is something that happens instantaneously. So the program above is going to check for pid, attempting to kill it gracefully .. If the kill -15 fails -- The kill -9 is performed. The way it knows that kill -15 failed, is the grep command. If kill -15 was successful, that pid should not exist any longer, making the following grep return empty.
So really, kill -9 only runs if kill -15 failed to gracefully stop the program. The problem with this approach, is that sometimes gracefully stopping a process can take some time depending on the program. So IMHO there needs to be a wait period or a sleep for a few seconds to allow kill -15 to attempt to gracefully stop the process .. Most assuredly with the approach above, kill -9 is almost always invoked since the script doesn't allow much time for the process to be shut down properly. In the event that kill -15 is still processing, kill -9 will just override and instantly stop the process.
If you have the option to refactor, you can use /proc/$PID as a more efficient way to detect if a process is running.
stopSvc() { local svc=$1
read x pid x < <( ps -fu "$App_user" | grep -E " ($App_baseDIR/$1/|)$svc.jar$" ||: )
local -i starting="$(date +%s)" # linux epoch timestamp in seconds
while [[ -d "/proc/$pid" ]]
do ps -fp "$pid"
kill -term "$pid"
if (( ( $(date +%s) - starting ) < 20 )) # been trying for less than 20s
then sleep 2
date
else echo "$svc is hung - using a hard stop"
kill -KILL "$pid"
break
fi
done
sleep 2
[[ -d "/proc/$pid" ]] && return 1 || return 0 # flip the return
}
Basically, the kill -15 is a term signal, which the process could catch to trigger a graceful shutdown, closing pipes, sockets, & files, cleaning up temp space, etc, so to be useful it should give some time. The -9 is a kill and can't be caught. It's the Big Hammer that you use to squish the jobs that are misbehaving, and should be reserved for those cases.
You are totally right, this makes little sense. If you're going to use the -9 so soon, might as well skip the careless attempt at better practice and just remove the -15.

Bash: Killing all processes in subprocess

In bash I can get the process ID (pid) of the last subprocess through the $! variable. I can then kill this subprocess before it finishes:
(sleep 5) & pid=$!
kill -9 $pid
This works as advertised. If I now extend the subprocess with more commands after the sleep, the sleep command continues after the subprocess is killed, even though the other commands never get executed.
As an example, consider the following, which spins up a subprocess and monitor its assassination using ps:
# Start subprocess and get its pid
(sleep 5; echo done) & pid=$!
# grep for subprocess
echo "grep before kill:"
ps aux | grep "$pid\|sleep 5"
# Kill the subprocess
echo
echo "Killing process $pid"
kill -9 $pid
# grep for subprocess
echo
echo "grep after kill:"
ps aux | grep "$pid\|sleep 5"
# Wait for sleep to finish
sleep 6
# grep for subprocess
echo
echo "grep after sleep is finished:"
ps aux | grep "$pid\|sleep 5"
If I save this to a file named filename and run it, I get this printout:
grep before kill:
username 7464 <...> bash filename
username 7466 <...> sleep 5
username 7467 <...> grep 7464\|sleep 5
Killing process 7464
grep after kill:
username 7466 <...> sleep 5
username 7469 <...> grep 7464\|sleep 5
grep after sleep is finished:
username 7472 <...> grep 7464\|sleep 5
where unimportant information from the ps command is replaced with <...>. It looks like the kill has killed the overall bash execution of filename, while leaving sleep running.
How can I correctly kill the entire subprocess?
You can set a trap in the subshell to kill any active jobs before exiting:
(trap 'kill $(jobs -p)' EXIT; sleep 5; echo done ) & pid=$!
I don't know exactly why that sleep process gets orphaned, anyway instead kill you can use pkill with -P flag to also kill all children
pkill -TERM -P $pid
EDIT:
that means that in order to kill a process and all it's children you should use instead
CPIDS=`pgrep -P $pid` # gets pids of child processes
kill -9 $pid
for cpid in $CPIDS ; do kill -9 $cpid ; done
You can have a look at rkill that seems to meet your requirements :
http://www.unix.com/man-page/debian/1/rkill/
rkill [-SIG] pid/name...
When invoked as rkill, this utility does not display information about the processes, but
sends them all a signal instead. If not specified on the command line, a terminate
(SIGTERM) signal is sent.

Wait for arbitrary process and get its exit code in Linux

Is there a way to wait until a process finishes if I'm not the one who started it?
e.g. if I ran "ps -ef" and pick any PID (assuming I have rights to access process information) - is there a way I can wait until the PID completes and get its exit code?
You could use strace, which tracks signals and system calls. The following command waits until a program is done, then prints its exit code:
$ strace -e none -e exit_group -p $PID # process calls exit(1)
Process 23541 attached - interrupt to quit
exit_group(1) = ?
Process 23541 detached
$ strace -e none -e exit_group -p $PID # ^C at the keyboard
Process 22979 attached - interrupt to quit
--- SIGINT (Interrupt) # 0 (0) ---
Process 22979 detached
$ strace -e none -e exit_group -p $PID # kill -9 $PID
Process 22983 attached - interrupt to quit
+++ killed by SIGKILL +++
Signals from ^Z, fg and kill -USR1 get printed too. Either way, you'll need to use sed if you want to use the exit code in a shell script.
If that's too much shell code, you can use a program I hacked together in C a while back. It uses ptrace() to catch signals and exit codes of pids. (It has rough edges and may not work in all situations.)
I hope that helps!
is there a way I can wait until the PID completes and get its exit code
Yes, if the process is not being ptraced by somebody else, you can PTRACE_ATTACH to it, and get notified about various events (e.g. signals received), and about its exit.
Beware, this is quite complicated to handle properly.
If you can live without the exit code:
tail --pid=$pid -f /dev/null
If you know the process ID you can make use of the wait command which is a bash builtin:
wait PID
You can get the PID of the last command run in bash using $!. Or, you can grep for it with from the output of ps.
In fact, the wait command is a useful way to run parralel command in bash. Here's an example:
# Start the processes in parallel...
./script1.sh 1>/dev/null 2>&1 &
pid1=$!
./script2.sh 1>/dev/null 2>&1 &
pid2=$!
./script3.sh 1>/dev/null 2>&1 &
pid3=$!
./script4.sh 1>/dev/null 2>&1 &
pid4=$!
# Wait for processes to finish...
echo -ne "Commands sent... "
wait $pid1
err1=$?
wait $pid2
err2=$?
wait $pid3
err3=$?
wait $pid4
err4=$?
# Do something useful with the return codes...
if [ $err1 -eq 0 -a $err2 -eq 0 -a $err3 -eq 0 -a $err4 -eq 0 ]
then
echo "pass"
else
echo "fail"
fi

Resources