3

I have a bash script that looks like this:

bundle exec middleman server & node script.js && 
kill -9 $(lsof -i:4567 -t) &&
bundle exec middleman build --verbose

Right now, the way I kill the bundle exec middleman server is by killing based on the port (localhost:4567). However, this is not good in case the port needs to change (which it would).

What is the best way to kill the bundle exec middleman server after running the node script.js (which basically waits for the server to be online, sends a get request and does something with the server data returned). I want to do something that isn't dependent on the port and just kills it by name or second most recent thing run (or most recent server run?)

Thank you very much!

  • $! returns the pid of the last command. – jordanm Jul 26 at 14:03
  • @jordanm how would I go about getting the pid of the second last command? since the last command would be the node script, no? – The Computer Scientist Jul 26 at 15:27
  • @TheComputerScientist - in this case, kill $! and kill %+ would usually do the same thing, because $! is the PID of the most recently backgrounded job. The difference is that PIDs can be reused, so on a heavily loaded system, it's theoretically possible that bundle has exited and something else is using that PID. Using a jobspec (with Bash's built-in kill) is safer, as the jobspec only refers to backgrounded jobs in the current shell process. If bundle exited for some reason, there will not be a %+ job to kill unless you also backgrounded something else inside this script. – dannysauer Jul 26 at 18:56
1

Depending on the shell, you should be able to easily kill the backgrounded task. If you're not running anything else in the background, it'll be job 1, so you can just kill %1:

sauer@host:~$ set -b
sauer@host:~$ sleep 10 & echo hello
[1] 18988
hello
sauer@host:~$ kill %1
[1]+  Terminated              sleep 10

If you might have other things in the background, you can do a couple of things. Assuming Bash or a shell that works similarly, you can either use jobs -r to get a list of running jobs and grep the job number out, or you can specify a process name in the jobspec (the thing after the percent) instead of a number. Probably kill %bundle. Or, even most useful in this case, you can use %+ to refer to the most recently backgrounded job.

sauer@host:~$ set -b
sauer@host:~$ sleep 10 & sleep 11 & echo hello
[1] 19406
[2] 19407
hello
sauer@host:~$ kill %+
[2]+  Terminated              sleep 11

Note that there were two sleep processes running in the background, but the %+ was the "most recent" one, so it's what was killed. Also set -b just enables immediate feedback on the background job status instead of waiting until the next prompt. That's just for the example. :)

Oh, and here's an additional useful example demonstrating killing background tasks by name and what happens if the pattern matches multiple processes, since it's on-topic. Notice that the "jobs" output shows the + and - indicators for the most recent and second-most-recent jobs, usable as shorthand in the jobspec.

sauer@host:~$ sleep 10 & sleep 11 & sleep 9 & echo hello
[1] 22255
[2] 22256
[3] 22257
hello
sauer@host:~$ jobs
[1]   Running                 sleep 10 &
[2]-  Running                 sleep 11 &
[3]+  Running                 sleep 9 &
sauer@host:~$ kill %sleep
-bash: kill: sleep: ambiguous job spec
sauer@host:~$ kill %"sleep 10"
[1]   Terminated              sleep 10
  • Hey Danny, I don't quite understand what is "you can specify a process name in the jobspec (the thing after the percent) instead of a number". What do you mean by this? Is this process name always the same/consistent whenever middleman server is run? – The Computer Scientist Jul 26 at 15:32
  • The process name will almost always be the program typed on the command line. If you run it manually once and type "jobs", you'll see the name it's looking for. Does the extra example I added at the end help explain that? – dannysauer Jul 26 at 18:38
  • Either way, the kill %+ is probably what you want, as you want to kill "the job most recently launched in the background". The by-name selection is really only going to be useful if you run multiple things in the background. – dannysauer Jul 26 at 18:39
  • This is great, thanks! – The Computer Scientist Jul 26 at 21:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.