Sunday, September 28, 2008

UNIX one-liner to kill a hanging Firefox process

Here's a useful one-liner that uses awk (and grep, sort and sed too), to kill a Firefox process that has hung.

Firefox hung just now on my machine - so I ran this command:

# kill -HUP ` ps -aef | grep -i firefox | sort -k 2 -r | sed 1d | awk ' { print $2 } ' `


NOTE: That's sed space one d in the line above, i.e. the digit "one", not the letter "ell".

The command does all of the following:

- Uses the ps command to get a list of all running processes; the list is written to standard output.

- Pipes that to grep -i firefox to identify all Firefox-related processes (this is needed because, on Ubuntu Linux, there is more than one such process (even for a single running Firefox instance), because the firefox command you run is a shell script which calls another script which finally calls the real firefox binary).

- Pipes that to sort -k 2 -r to sort the output in descending order by the process-id (2nd field of the ps output).

- Pipes that to sed 1d to delete the line of output that refers to the grep in the pipeline itself - otherwise I'd end up killing the grep as well (because grep -i firefox matches the line for the grep process as well as the actual Firefox-related processes).

NOTE: This part (using sed 1d to kill the grep) is based on knowing that the grep process is the process that currently has the highest-numbered process id (due to the preceding sort command), of all the processes that match the grep pattern. So it'll be the first line of output, so sed 1d deletes it (and passes all the other lines untouched, to the next command in the pipeline).

- Pipes that to awk ' { print $2 } ' to extract only the 2nd field, the process-id, from each line.

- And, since the entire part of the command after the HUP is enclosed in backward quotes (also called backticks or grave accents), what happens is that the final output of the commands between the backticks replaces the backticks and everything between them, so what the shell finally sees before it runs the kill command, is something like this:

kill -HUP 8849 8845 8833

- which results in automagically killing all (and only) the processes related to the single instance of Firefox that was running (but hung) on my machine.

WARNING: Don't try this command (exactly as shown) if you're on a Linux system with multiple users, since it would end up deleting all their running Firefox processes as well - and don't run it even if you yourself are running multiple instances of Firefox and only want to kill one of them.

NOTE: The sort command uses the -r option to list the processes in reverse numeric order by process-id, so that we kill each child before its parent, to avoid creating orphan processes.

Vasudev Ram.

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

11 comments:

Anonymous said...

Test comment.
- Vasudev

Anonymous said...

Maybe you should look into the killall command.

Anonymous said...

Have you tried

On Pre-Heron
killall firefox-bin

On Heron:
killall firefox

Much simpler.

Anonymous said...

or 'pkill [sig] firefox' on systems with pkill installed.

Anonymous said...

The sort seems unnecessary for several reasons. First, is that 'ps' reports the pids in order to begin with. Second, it would not matter what order you kill the processes in -- you already have the list of pids to kill. If you killed a parent before a child that would not effect the child's pid number. Third, you shouldn't get orphaned processes anyways since any child processes will get the same signal sent to a parent (unless explicitly set not to or if daemonized).

Vasudev Ram said...

Thanks for all the comments, guys. Interesting. I did read all of them. I have some doubts and remarks on some of them - but will check those points out first and then reply.

- Vasudev

Anonymous said...

As anonymous said, pkill is the right tool for this particular job, but here are some comments:

- If you are only interested in your own processes, skip the -aef options to ps
- If you do not want to use pgrep/pkill, you could use something like grep -i [f]irefox and avoud the sed part altogether (the brackets make grep not longer match its own process)

Vasudev Ram said...

Was busy for a while ...

I looked into some of the suggestions in the comments.

@anonymous #1 - who mentioned killall:

Yes, that looks like it should work. I knew about killall earlier on UNIX but hadn't used it recently so wasn't aware of, for example, the -u, -g and -r options to it. Good to know of those options, anyway - thanks.

Referring to my original post:

I can see that the -u option (for user) can help me not kill other users' processes, though it won't prevent me from killing my own other Firefox processes which are not hung (if I have more than one running).

And maybe if I use the -g option (for process group), I can kill all the related Firefox processes that are created by my initial firefox command (such as the shell scripts I mentioned). That would depend on whether they all belong to the same process group, which I need to check by looking up the man pages, one of the Stevens UNIX books, or by writing a test C program to check it out (i.e. create a process with child and grandchild and print the process group id of each.

@anonymous #2 (who mentioned Pre-Heron and Heron):

I'm on pre-Heron. Will try on Heron after installing it later. Interesting about the difference between the commands needed for Heron and pre-Heron. Due to a difference in how the firefox command is implemented in them, I guess.

@ those who mentioned pkill:

pkill looks interesting. As does pgrep. Running file `which pkill` shows that pkill is a symlink to pgrep. Will check them both out a little later and then reply.

@anonymous #4 (who said the sort seems unnecessary):

>If you killed a parent before a child that would not effect the child's pid number.

You're right about that. I forgot - I was thinking about the child's ppid (parent process id) which does get changed - since the child gets adopted by the init process (whose pid is 1) when the parent is killed. But a changed ppid is not the same as a changed pid. So the child would retain its original pid hence and still get killed, irrespective of its becoming an orphan (for a short while). Which leads me to my next point - I think you're partly right and partly wrong about my script not creating orphaned processes (if no sort is used). My understanding is that if the pids were not sorted in descending order (i.e. were in random order or even ascending order - see next point), a parent could get killed before one of its children, which would make the child an orphan for a short duration, but it would then be killed anyway because it's pid is in the list of pids as you say. So, bottomline - orphans would be created but get killed soon thereafter.

As far as your first point goes (that I don't need sort because ps output is already sorted) - again, I was going by my memory of how ps output was earlier on UNIX; IIRC, it wasn't sorted - that's why I used to use that kind of one-liner earlier (on UNIXes). Also, I note now that the ps output is sorted on Ubuntu (Linux), but in ascending order. Which means that I'd still have the (temporary) orphans if I didn't explicitly sort in reverse order by pid, since all parents would appear in the list before their children. Unless, of course, I used one of the sort options to ps that I now see shown in its man page ... wow, it gets hairier and hairier ... :-)

Good fun!

Vasudev Ram said...

@ anonymous #5 (who said pkill is the right tool for this particular job):

>If you are only interested in your own processes, skip the -aef options to ps

True - good simplification.

>If you do not want to use pgrep/pkill, you could use something like grep -i [f]irefox and avoud the sed part altogether (the brackets make grep not longer match its own process)

Didn't know about that regexp trick - nice one.

Rashi said...

Vasudev,

Awk is very helpful; thanks for posting on awk.

Some of the posts from my blog:

http://unstableme.blogspot.com/search/label/Awk

// Jadu

Vasudev Ram said...

Mario Grgic: Thanks for the suggestion. [Missed publishing it earlier.] I'll have to try that version to confirm it works the same as what I originally wanted (and can't test right now, as I'm on Windows at the moment, will do so later and post another comment), but you're probably right. If so, that's quite a simplification.

About killall - see my comment above in reply to anonymous #1.