Prevent process from killing itself using pkill
You can explicitly filter out the current PID from the results:
kill $(pgrep -f $DAEMON | grep -v ^$$\$)
To correctly use the -f
flag, be sure to supply the whole path to the daemon rather than just a substring. That will prevent you from killing the script (and eliminate the need for the above grep
) and also from killing all other system processes that happen to share the daemon's name.
Find and kill a process in one line using bash and regex
In bash
, you should be able to do:
kill $(ps aux | grep '[p]ython csp_build.py' | awk '{print $2}')
Details on its workings are as follows:
- The
ps
gives you the list of all the processes. - The
grep
filters that based on your search string,[p]
is a trick to stop you picking up the actualgrep
process itself. - The
awk
just gives you the second field of each line, which is the PID. - The
$(x)
construct means to executex
then take its output and put it on the command line. The output of thatps
pipeline inside that construct above is the list of process IDs so you end up with a command likekill 1234 1122 7654
.
Here's a transcript showing it in action:
pax> sleep 3600 &
[1] 2225
pax> sleep 3600 &
[2] 2226
pax> sleep 3600 &
[3] 2227
pax> sleep 3600 &
[4] 2228
pax> sleep 3600 &
[5] 2229
pax> kill $(ps aux | grep '[s]leep' | awk '{print $2}')
[5]+ Terminated sleep 3600
[1] Terminated sleep 3600
[2] Terminated sleep 3600
[3]- Terminated sleep 3600
[4]+ Terminated sleep 3600
and you can see it terminating all the sleepers.
Explaining the grep '[p]ython csp_build.py'
bit in a bit more detail:
When you do sleep 3600 &
followed by ps -ef | grep sleep
, you tend to get two processes with sleep
in it, the sleep 3600
and the grep sleep
(because they both have sleep
in them, that's not rocket science).
However, ps -ef | grep '[s]leep'
won't create a process with sleep
in it, it instead creates grep '[s]leep'
and here's the tricky bit: the grep
doesn't find it because it's looking for the regular expression "any character from the character class [s]
(which is s
) followed by leep
.
In other words, it's looking for sleep
but the grep process is grep '[s]leep'
which doesn't have sleep
in it.
When I was shown this (by someone here on SO), I immediately started using it because
- it's one less process than adding
| grep -v grep
; and - it's elegant and sneaky, a rare combination :-)
How to kill all processes with a given partial name?
Use pkill -f
, which matches the pattern for any part of the command line
pkill -f my_pattern
Just in case it doesn't work, try to use this one as well:
pkill -9 -f my_pattern
My shell cannot prevent ctrl+c from killing itself
I wonder why ash
or other bash could work, so dig into ash
's source code. I try this snippets.
It works.
int ofd;
ofd = fd = open(_PATH_TTY, O_RDWR);
if (fd < 0) {
/* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
* That sometimes helps to acquire controlling tty.
* Obviously, a workaround for bugs when someone
* failed to provide a controlling tty to bash! :) */
fd = 2;
while (!isatty(fd))
if (--fd < 0)
goto out;
}
/* fd is a tty at this point */
fd = fcntl(fd, F_DUPFD, 10);
if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
close(ofd);
if (fd < 0)
goto out; /* F_DUPFD failed */
close_on_exec_on(fd);
while (1) { /* while we are in the background */
pgrp = tcgetpgrp(fd);
if (pgrp < 0) {
out:
ash_msg("can't access tty; job control turned off");
mflag = on = 0;
goto close;
}
if (pgrp == getpgrp())
break;
killpg(0, SIGTTIN);
}
initialpgrp = pgrp;
setsignal(SIGTSTP);
setsignal(SIGTTOU);
setsignal(SIGTTIN);
pgrp = rootpid;
setpgid(0, pgrp);
xtcsetpgrp(fd, pgrp);
Why does running pkill -f anything over ssh fail only when branching on its result?
The problem appears to be that pkill
is killing itself. Or rather, it is killing the shell that owns it.
First of all, it appears that ssh
uses the remote user's shell to execute certain "complicated" commands:
$ ssh user@remote 'ps -F --pid $$'
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
user 9531 9526 0 11862 1616 6 14:36 ? 00:00:00 ps -F --pid 9531
$ ssh user@remote 'ps -F --pid $$ && echo hi'
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
user 9581 9577 0 28316 1588 5 14:36 ? 00:00:00 bash -c ps -F --pid $$ && echo hi
hi
Second, it appears that pkill -f
normally knows not to kill itself (otherwise all pkill -f
commands would suicide). But if run from a subshell, that logic fails:
$ pkill -f fake_process; echo $?
1
$ sh -c 'pkill -f fake_process'; echo $?
[1] 14031 terminated sh -c 'pkill -f fake_process'
143
In my case, to fix this I just re-worked some of the code around my ssh
/pkill
so that I could avoid having a "complicated" remote command. Theoretically I think you could also do something like pgrep -f <cmd> | grep -v $$ | xargs kill
.
Related Topics
Linux Terminal: How to Capture or Watch Other Terminal Session
How to Limit the Cache Used by Copying So There Is Still Memory Available for Other Caches
How to Run Elasticsearch 2.1.1 as Root User in Linux MAChine
Calculating Rounded Percentage in Shell Script Without Using "Bc"
How to Specify Time in Cron Considering Year
Shell Script to Copy and Prepend Folder Name to Files from Multiple Subdirectories
What Does "$1/*" Mean in "For File in $1/*"
Iterating Over Lists in Makefiles
Configure and Build Opencv to Custom Ffmpeg Install
"Current" in Linux Kernel Code
When Should the Option Remainafterexit Needs to Be Set True When Creating New Systemd Services
Execution Time of an SQLite Query: Units
How to Tail -F the Latest Log File with a Given Pattern
Why Gcc 4.X Default Reserve 8 Bytes for Stack on Linux When Calling a Method
How to Use Git Namespace to Hide Branches
Bluetooth Low Energy in C - Using Bluez to Create a Gatt Server