8

My script accepts a process name as an input and kills it. I tried using pgrep but it's returning two PIDs , one for the process which is running and one for the script which accepts the process name as input, so am stuck! I tried using the pgrep -fo option too but that did not help either. Any suggestions would be helpful. This is my script

#!/bin/bash
ProcessName=$1

pID= pgrep -fl $ProcessName

echo $pID

So, when I invoke the script, it's returning two PIDs:

bash-3.00$ ./dynamic_values.sh test-Process

10534 /xxx/xxo/xxx/xxe --run --propFile /application/test/test-Process_Archive.tra --innerProcess
23401 /bin/bash ./dynamic_values.sh test-Process

I was expecting just 10534, but it picked up the script too . Version of OS just in case:

bash-3.00$ uname -a
Linux xxxxxx 2.6.9-67.0.1.
  • Why write a script for this? Lots of tools have already been written for these kind of jobs, you just need to find the right one. Based on your question, I would suggest you try pkill. It uses the same process findng logic as pgrep so you already know how to use it to find your process, but rather than returning the PID's to you, it just goes ahead and sends them a kill signal for you. In the mean time, it also takes care of details such as not killing itself. – Caleb Aug 29 '12 at 10:20
  • pkill when using -f (which he is doing) will have the same problem. – bahamat Aug 29 '12 at 15:30
  • @bahamat: Really? So do you have to use -x in combination with -f to make sure you are matching the whole thing? I'm surprised pkill doesn't have a built in way to handle this. – Caleb Aug 29 '12 at 16:24
  • @Caleb From what I've experienced, on OS X and Solaris it does the right thing, but Linux uses a different implementation. I had to get real targeted with my regexp to get what I wanted on Linux (I was writing a script that would kill old instances of itself). – bahamat Aug 29 '12 at 16:28
  • I have never had pkill kill itself before killing the processes I wanted to kill, so I'd always assumed the implementation was good. – jw013 Aug 29 '12 at 18:40
  • @jw013 pkill and pgrep are identical except that one prints the pids and the other one sends a signal. They take care never to match themselves, but they can match their caller. – Gilles 'SO- stop being evil' Aug 29 '12 at 22:50
  • "Why run a script for this?" - Maybe it's the minimal amount of code to reproduce the issue... – Owl Jan 17 '22 at 13:07

4 Answers4

3

I had to tackle this same problem a couple of weeks ago. pgrep and pkill support extended regular expressions so it's a simple matter of getting the right regexp.

This is your script with the regexp that I used.

#!/bin/bash
ProcessName=$1

pID= pgrep -fl "^(/.*)?${ProcessName}\s"

echo $pID

Although using pkill (as Caleb suggested) is better.

pkill -fl "^(/.*)?${ProcessName}\s"

You may still need to tweak the regexp to get the desired results for your use case and how the program is being executed.

Now, if there are actually multiple processes running with that name they will of course be killed. If you want to avoid that you can use -o to kill only the oldest matching process or -n to kill only the newest. If you want only one, but neither the oldest or newest then you probably shouldn't be using p(kill|grep).

bahamat
  • 39,666
  • 4
  • 75
  • 104
1

Wouldn't using

| grep -v $$

to exclude your process from the list help?

Didi Kohen
  • 1,841
1
#!/bin/bash

ProcessName=$1

pID=`pgrep -fl $ProcessName`

echo "$pID" | grep -v  "^$$"
  • The point of pgrep and pkill is that you don't have to pipe it to grep. – bahamat Aug 29 '12 at 15:38
  • 1
    it depends. in this case we should filter out current process by it's pid – hostmaster Aug 29 '12 at 20:15
  • No, you don't understand. The one and only point of pgrep is to not pipe to grep. If you're going to use grep you might as well use ps | grep. – bahamat Aug 29 '12 at 20:34
  • I am afraid you have misunderstanding here. main point of prep look up processes based on name and other attributes – hostmaster Aug 30 '12 at 06:58
  • 2
    Years ago during the Solaris start up every init script called the equivalent of kill $(ps -ef | grep somedaemon | grep -v grep | awk '{print $2}'). The extra forks were increasing the boot up time by launching 5x the number of processes necessary. pkill and pgrep were written so you could just call pkill somedaemon and significantly reduce boot up times. – bahamat Aug 30 '12 at 18:01
0

if you exclude the #!/bin/bash then it will not fork another process for the script but you will lose the choice of what shell it runs with. bash is default enough though and those that are smiler should be able to run this.

not sure if that will get rid of the second process ID though.

I understand this is not complete but it is late and I have to work in the am but this "should" work as a quick fix.

Joe
  • 1,306
  • thanks for taking time this late in the evening , unfortunately it returns an empty string as well as the correct pid,like this bash-3.00$ ./dynamic_values.sh test-Process 10534 /opt/XXengine --run --propFile /opt/application/test/test-Process_Archive.tra --innerProcess $ – greenhorn Aug 29 '12 at 03:58