ryanwhocodes Feb 25, 2018 · 5 min read

Find and Stop Port Processes on a Mac Using Bash

Learn to stop your app processes running on specific ports by using the command line to kill the PID.

This post will show you how to find and stop processes attached to ports you want to free, and how to create Bash functions to easily call these methods.

Contents

The problem

Is the below all too familiar?

    $ rails server
    => Booting Puma
    => Rails 5.1.4 application starting in development
    => Run `rails server -h` for more startup options
    A server is already running. Check /Users/<username>/project/tmp/pids/server.pid.
    Exiting

When developing applications, such as with Ruby on Rails or Docker, sometimes you may exit a program but a server or port may still be in use. This means that when you try to reload it, you get an error saying a server is running or the port is already allocated.

This post will show you how to create a shell function so you can enter a command, such as free-port 3000, in your terminal to exit the process running on the busy port so you can use it again.

The first step is to identify to process using the blocked port…

Find the IDs of processes using a port

View the process IDs of the ports being used with the following command:

    lsof -t -i :YOUR_PORT_NUMBER

For example, to find the process ID of the Ruby on Rails server running on the default port of 3000, you would use:

    $ lsof -t -i :3000
    => 13980

A breakdown of this command:

  • lsof — list open files
  • :3000 followed by the port number (3000 used in this example) tells the command to just select this port
  • The options are explained in detail in the man page for lsof
    -i [i]

    selects the listing of files any of whose Internet address matches the  
    address specified in i. If no address is specified, this option selects the  
    listing of all Internet and x.25 (HP-UX) network files.  

    -t  

    specifies that lsof should produce terse output with process identifiers  
    only and no header — e.g., so that the output may be piped to kill(1).

Kill the process

You could kill all processes on all ports if you don’t specify a port number.

But you’ll most likely know the blocked port, and therefore the following will just kill the process associated with that port.

    kill $(lsof -t -i :YOUR_PORT_NUMBER)

Command substitution allows the output of a command to be substituted in place of the command name itself. $(command) — StackExchange: Unix & Linux: Have backticks (i.e. `cmd`) in shells been deprecated?

The above kill command will by default send a software termination signal to the process (SIGTERM). If this doesn’t work, the force kill version (SIGKILL) is specified with the option -9 or the English word equivalent -kill.

    kill -kill $(lsof -t -i :YOUR_PORT_NUMBER)

SIGTERM is the termination signal. The default behavior is to terminate the process, but it also can be caught or ignored. The intention is to kill the process, gracefully or not, but to first allow it a chance to cleanup. SIGKILL is the kill signal. The only behavior is to kill the process, immediately. As the process cannot catch the signal, it cannot cleanup, and thus this is a signal of last resort. — Quora: What is the difference between the SIGINT and SIGTERM signals in Linux? What’s the difference between the SIGKILL and SIGSTOP signals?

What if you don’t want to try to remember that long command and type it out into the command line each time?

Answer: create your own shell functions.

Adding them as Bash functions

Now that you have freed up your ports, you can restart that server or application and carry on developing with the knowledge that you can easily unblock ports with a single command.

You can automate this further by adding them as Bash functions (or for another shell, such as Zsh) that take the argument (shown below by the variable $1) of the port number to unblock.

    echo 'free-port() { kill "$(lsof -t -i :$1)"; }
    kill-port() { kill -kill "$(lsof -t -i :$1)"; }' \
    >> ~/.bashrc && source ~/.bashrc

NOTE: Customise them with your own names — free-port and kill-port are just ideas for them!

Time to try these out…

The solution

Now you can use them directly in Bash!

    $ rails server
    => Booting Puma
    => Rails 5.1.4 application starting in development
    => Run `rails server -h` for more startup options
    Puma starting in single mode…
    * Listening on tcp://0.0.0.0:3000

In a new terminal tab or window use the function, passing the Ruby on Rails server port of 3000 as the argument:

    $ free-port 3000

And viola! The Rails server process gracefully exits and is now free to use again.

    - Gracefully stopping, waiting for requests to finish
    === puma shutdown: 2018–02–25 17:56:27 +0000 ===
    - Goodbye!
    Exiting
    terminated rails server

Find out more

The more you learn about the commands used to manage processes, the more control you have over running your apps.

Why not have a go at customising the script?

Here are some resources if you want to learn more about the commands involved with viewing and stopping processes.