pkill can't kill processes with parent process id 1
pkill
by default sends the SIGTERM
signal to processes to stop. Here's a list of the signals you can send a process. You can send them by name or number typically:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
So you're sending signal # 15. If the processes are not responding to this signal then you may need to use signal #9, pkill -SIGKILL
.
From the man page of pkill:
-signal
Defines the signal to send to each matched process. Either the numeric or the symbolic signal name can be used. (pkill only.)
Issues with pkill
The OP mentioned that he was unsuccessful in getting pkill -SIGKILL "run_tcp"
to work. We initially thought that the issue had to do with pkill
potentially killing itself before it had finished killing all the "run_tcp" processes.
But that was hard to accept given a foot note in the pkill
man page:
The running pgrep or pkill process will never report itself as a match.
In addition to that, @Gilles left a comment basically saying the same thing, that pkill
just does not kill itself. Then he gave us a pretty big clue as to what was actually going on.
Here's an example that demonstrates what the OP and myself were missing:
step 1 - make a sleepy.bash script
#!/bin/bash
sleep 10000
step 2 - load up some fake sleep tasks
$ for i in `seq 1 5`;do bash sleepy.bash & done
[1] 12703
[2] 12704
[3] 12705
[4] 12706
[5] 12707
step 3 - check the running tasks
$ ps -eaf|egrep "sleep 10000|sleepy"
saml 12703 29636 0 21:48 pts/16 00:00:00 bash sleepy.bash
saml 12704 29636 0 21:48 pts/16 00:00:00 bash sleepy.bash
saml 12705 29636 0 21:48 pts/16 00:00:00 bash sleepy.bash
saml 12706 29636 0 21:48 pts/16 00:00:00 bash sleepy.bash
saml 12707 29636 0 21:48 pts/16 00:00:00 bash sleepy.bash
saml 12708 12704 0 21:48 pts/16 00:00:00 sleep 10000
saml 12709 12707 0 21:48 pts/16 00:00:00 sleep 10000
saml 12710 12705 0 21:48 pts/16 00:00:00 sleep 10000
saml 12711 12703 0 21:48 pts/16 00:00:00 sleep 10000
saml 12712 12706 0 21:48 pts/16 00:00:00 sleep 10000
step 4 - try using my pkill
$ pkill -SIGTERM sleepy.bash
step 5 - what happened?
Doing the ps
command from above, we see that none of the processes were killed, just like the OPs issue. What's going on?
Turns out this is an issue in how we were attempting to make use of pkill
. The command:
pkill -SIGTERM "sleepy.bash"
was looking for a process by the name of "sleepy.bash". Well there aren't any processes by that name. There's processes that are named "bash sleepy.bash" though. So pkill
was looking for processes to kill and not finding any and then exiting.
So if we slightly adjust the pkill
we're using to this:
$ pkill -SIGTERM -f "sleepy.bash"
[1] Terminated bash sleepy.bash
[2] Terminated bash sleepy.bash
[3] Terminated bash sleepy.bash
[4]- Terminated bash sleepy.bash
[5]+ Terminated bash sleepy.bash
Now we get the effect we were looking for. What the difference? We made use of the -f
switch to pkill
which makes pkill
use the entire command line path when matching vs. just the process name.
from pkill man page
-f The pattern is normally only matched against the process name.
When -f is set, the full command line is used.
Alternative methods
kill, ps
This method is pretty verbose but does the job as well:
kill -9 $(ps -ef|grep "run_tcp"|grep -v "grep"|awk '{print $2}')
pgrep w/ pkill & killall
You can use either pgrep
to feed a list of PIDs to pkill
or make use of killall
instead.
Examples
# pgrep solution
$ pgrep "run_tcp" | pkill -SIGKILL
# killall
killall -SIGKILL -r run_tcp
References
- pgrep man page
- pkill man page
- killall man page
This is unrelated to the parent process ID. The problem is simply that you are killing all the processes running run_tcp_sender.sh
, but you have no such processes — the processes you're interested in are running bash
.
You can instruct pkill
to match on the whole command line:
pkill -f '^bash run_tcp_sender.sh'
Another approach would be to kill all the processes that have the script open. That could make collateral damage, e.g. to an editor that was just opening the script.
fuser -k /path/to/run_tcp_sender.sh
As long as you aren't editing the script as root, killing only root's processes would solve that issue:
kill $(lsof -uroot /path/to/run_tcp_sender.sh)