I have a script that starts firefox for 4 seconds, then kills it. Firefox will automatically log into a captive portal, so I only need it to be open for 4 seconds, as soon as the wifi connects. I am on Ubuntu 13.04.

My problem seems to be that $pid isn't set.

firefox ; pid=$!
sleep 4
kill $pid

EDIT: removed set, and now it gives kill an invalid pid.

  • 2
    N.B. $! is the PID (process ID) of last job run in background, so you'd have to replace ; with & at the very least. Not that this would solve your main problem. Oct 21, 2013 at 17:22
  • I know that does does not answer the question, but why use firefox to log in via the captive portal? That is like going rowing with a battleship. Wget or curl are much more lightweight. (Link to curl example).
    – Hennes
    Oct 21, 2013 at 18:14
  • 1
    Related: Bash Run command for certain time?
    – mpy
    Oct 21, 2013 at 19:20
  • @Hennes I also wanted to login to a captive portal. Wget and curl failed for me (maybe because of javascript elements or similar things). I finally succeeded using elinks. Not as lightweight as curl or wget, but much better than firefox.
    – Tim
    Oct 23, 2013 at 13:24
  • @Tim The problem here is that it has some fancy javascript that needs running so it will work. Oct 23, 2013 at 19:26

5 Answers 5


Your script does not work, because it waits until the firefox process has ended and afterwards executes pid=$!and the other command.

An easy way to do what you want is timeout:

timeout 4s firefox

It starts the program provided after the first argument and stops it after the time given as the first argument has passed.

  • What is timeout? I don't think it is part of standard Linux installations.
    – jaychris
    Oct 21, 2013 at 21:27
  • 1
    @jaychris It comes with coreutils, so it should be part of a standard installation.
    – Tim
    Oct 22, 2013 at 6:12
  • It seems to be missing on my Ubuntu server. (Not the most recent Ubuntu, but apt-get easily fixed that).
    – Hennes
    Oct 23, 2013 at 16:03
  • so awesome, shell scripting in Jenkins and had a show logs command that could only be control Zed to exit, except timeout, that works!
    – edencorbin
    Jun 10, 2018 at 1:41

The reason your pid=$! fails is that $! is the PID of last job run in background.


$ foo & echo $!

will start foo and echo the PID of its process.

In your case, firefox ; pid=$! would need to be replaced with firefox & pid=$! but it might be pretty useless because firefox is a script which execs the actual binary.

What you need to do is either use killall (which will try to kill all the instances firefox, whether yours or other users') or (copy and) edit the /usr/bin/firefox script to echo the new PID.

  • why downvote?..
    – sds
    Aug 21, 2014 at 13:15

A few more solutions.

  • killing firefox puts it in safe mode. That is undesirable. Oct 23, 2013 at 19:07

After following a few hints from the other answers, I came up with this messy script:

firefox -no-remote -p c-portal &
ffpid=`ps aux | grep firefox | sed '2q;d' | tr -s ' ' | cut -d ' ' -f 2`
echo "firefox pid: $ffpid"
sleep 4
kill $ffpid

I also needed to go into about:config and change browser.sessionstore.resume_from_crash to false.

Explanation of each command: ps aux gets the full list of processes on the system, grep finds all the ones containing firefox, sed gets the second line (which appears to always be the latest instance of firefox), tr removes the extra spaces, cut gets the second column (-d means delimiter, which is a space).

After that string-processing mess, there's a debug thing that prints out the PID of firefox, sleep for 4 seconds, so it can log in, then it kills firefox. The about:config setting prevents it from trying to restore the session.

  • 1
    A handy command to get a process id is pgrep.
    – Dean
    Oct 21, 2013 at 18:24
  • As Dean suggested, using pgrep firefox removes all the "string-processing mess". And really, using firefox for this is silly, slow and resource intensive. Just use curl or wget as Hennes suggested.
    – terdon
    Oct 21, 2013 at 19:04
  • @terdon I HAVE tried. Their silly captive portal runs some javascript that I can't seem to reverse-engineer the POST requests for. I have looked at it using wireshark, and my attempt to make it do what it's supposed to do fails horribly. It might be checking for if the browser has visited the captive portal page before actually doing anything. Oct 21, 2013 at 19:32
  • Fair enough, using firefox is much easier than deciphering other people's code.
    – terdon
    Oct 21, 2013 at 21:33
  • @terdon Especially when they don't really care about it being readable to others. Even more so, when they kind of don't want people reading it, as that could mess with their security. Oct 23, 2013 at 19:09

I'm not sure if it fits your situation, but you could use killall instead of kill. So it would be:

sleep 4
killall firefox

I think a more correct approach is to get the last firefox process using ps aux | grep firefox, but today I don't know how to do that treatment of returning only that highest process number using bash script.

  • Definitely not! Usually, I have a bunch of firefox instances running, and I don't want to kill all of them. ps aux | grep firefox does seem interesting, though. I will try it. Oct 21, 2013 at 16:32
  • @YetAnotherUser: you don't have a bunch of instances (processes), you have only one process displaying multiple windows and tabs. I'd suggest using a separate profile just for this, if possible. Oct 21, 2013 at 16:56
  • Separate profile? Hmmm yeah. I hacked together a long string of commands that gets the pid. Will post it shortly as soon as I get it completely working. Oct 21, 2013 at 17:08
  • Aside from the danger of killall (kill all firefoxes on Linux, kill a lot more Solaris), you might want to add a & after the firefox command. Else your sleep will not start until after you closed firefox.
    – Hennes
    Oct 23, 2013 at 16:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .