Managing multiple /etc/hosts files in Mac OS X

A while ago I wrote up a method for switching between /etc/hosts files. That post is pretty popular and clearly been useful to a few people.

Since then I’ve actually extended this method into a tool that can manage multiple /etc/hosts files. Using this new method you can have a folder that you can add hosts configurations to, and those files become available for switching into /etc/hosts straight away.

There’s no reason why an adaptation of this method wouldn’t work in Linux as well.

Here’s how you do it:

1. Create the host configuration directory

We’ll store all the /etc/hosts type files in /usr/local/share/hs.

You’ll need to do all of this as a root user. So switch to root using sudo -s first (you’ll need to be an administrator to do this).

$ mkdir -p /usr/local/share/hs
$ chmod 755 /usr/local/share/hs

Now to start with, let’s make a copy of the existing /etc/hosts file in this directory.

$ cp /etc/hosts /usr/local/share/hs/hosts.normal
$ chmod 744 /usr/local/share/hs/hosts.normal

Then make the real /etc/hosts a symbolic link to that new file.

$ ln -sf /usr/local/share/hs/hosts.normal /etc/hosts

Any additional host configurations in this folder need to be named using a similar hosts.* pattern.

2. Create the host switching script

Take the following bash script and save it to a file located at /usr/local/bin/hs


if [ $1 ]; then

# Change this if you put your host files elsewhere

echo "Attempting to switch host file to $HPATH$HFILE"

if [ ! -e $HPATH$HFILE ]; then
	echo "--> File does not exist!"
	echo "--> Exiting with status 1"
	exit 1

if [ -d $HPATH$HFILE ]; then
	echo "--> File is a directory!"
	echo "--> Exiting with status 2"
	exit 2

if [ -h $HPATH$HFILE ]; then
	echo "--> File is a symbolic link!"
	echo "--> Exiting with status 3"
	exit 3

if [ ! -h /etc/hosts ]; then
	echo "--> Current hosts file is a real file!"
	echo "--> Exiting with status 4"
	exit 4

# Link it up
sudo ln -sf $HPATH$HFILE /etc/hosts

# Flush the system-wide DNS cache
if [ -x /usr/bin/dscacheutil ]; then
	# Mac OS X 10.5
	/usr/bin/dscacheutil -flushcache
elif [ -x /usr/bin/lookupd ]; then
	# Mac OS X Less than 10.5
	/usr/bin/lookupd -flushcache
elif [ -x /usr/sbin/lookupd ]; then
	# Mac OS X Less than 10.5 (alternative)
	/usr/sbin/lookupd -flushcache

echo "--> Done"

The script does some basic validity checking on the file and also makes sure that /etc/hosts is just a symbolic link and not a real file.

You will need to adjust the permissions on this script so that only admins can run it.

$ chmod 750 /usr/local/bin/hs

You also need to make sure that /usr/local/bin is in your PATH so that the hs command can be found. We can test that.

$ echo $PATH

… will output something like …


If it’s not there then you need to add it in your users ~/.profile file. Add the following line to that file, you can create the file if it isn’t there.

export PATH=/usr/local/bin:$PATH

Now reload your profile and the hs command should be available.

$ . ~/.profile

You could also just close and open your terminal window to reload your profile.

3. Trying it out

The hs command takes one argument. The argument is used to specify the hosts configuration file to be loaded from /usr/local/share/hs. If no argument is given, then the assumed file is hosts.normal.

So for our first test we should add another hosts configuration.

$ cp /usr/local/share/hs/hosts.normal /usr/local/share/hs/hosts.test

Edit the new hosts configuration file to your liking.

Now we can try the switching command to switch to that configuration. You will need to supply your password if you are not already running as root.

$ hs test
Attempting to switch host file to /usr/local/share/hs/hosts.test
--> Done

The symbolic link at /etc/hosts should now be pointing to /usr/local/share/hs/hosts.test.

$ ls -l /etc/hosts
/etc/hosts -> /usr/local/share/hs/hosts.test

Now try switching back to your normal configuration.

$ hs
Attempting to switch host file to /usr/local/share/hs/hosts.normal
--> Done

Any more configurations that you add to /usr/local/share/hs are available this way.

Neat, huh?

4. Fancy schmancy tab completion

So that’s all great until you have 10 different hosts config files and you can’t remember their names.

The simple solution is to register additional commands so that command line tab completion can be used. The following additional script registers all the available hosts configs as separate commands. So instead of typing hs test we can type hstest. More importantly we can type hs then hit the “tab” key twice and get a full list of all available commands (one per configuration file).

Hard to explain, easier to just do. Add the following lines of code to the end of your ~/.profile file.

# Setup hs* commands
if [ -d $HSPATH ]; then
	for (( HSI=0 ; $HSI < $HSCOUNT ; HSI=$HSI+1 )); do
		alias hs$HSFILE='hs '$HSFILE

This script loops through all the files in /usr/local/share/hs and adds a command for each. Once that is added, reload your profile to make the script work.

$ . ~/.profile

Now you should be able to type hs then hit the “tab” key twice and get a list of the available commands.

$ hs TAB TAB
hs            hsnormal      hstest

If you add any new configuration files to /usr/local/share/hs you need to reload your profile for it to turn up as a new command (or just relaunch your terminal window).


  1. Simon Dorfman said:

    Hello Sam,

    Thanks for sharing this. Quite handy. Two things: a correction and a question.


    Under “3. trying it out”, the first command listed:

    cp /usr/local/share/hosts.normal /usr/local/share/hosts.test

    …should be:

    cp /usr/local/share/hs/hosts.normal /usr/local/share/hs/hosts.test


    I can’t seem to get the tab completion working. Any idea why I’m getting this error:?

    $ . ~/.profile
    -bash: /Users/simon/.profile: line 7: syntax error: `;’ unexpected
    -bash: /Users/simon/.profile: line 7: syntax error: `(( HSI=0 ; $HSI < $HSCOUNT ; HSI=$HSI+1 ))’


    • I’ll make that correction, thanks.

      Perhaps you copy/pasted the < entity instead of an actual “less than” sign?

  2. Simon Dorfman said:

    One other tip for my future self and others. To look up the I.P. address of the server you’re looking to connect to, run one of these two commands:



  3. RuBiCK said:


    I have setup some hosts in /etc/hosts but when I start my work VPN, the content of /etc/hosts is cleared. In all *unix the content of hosts file don’t change…

    Anyone knows if this behaviour on mac OS X is normally?


  4. Geraint said:

    Hi Sam,

    Great tutorial, I loved the first one and kept coming back to look it up every time I had to update my host file and this will probably help me remember where the settings are.

    One think tho, if you make :: alias hs$HSFILE=’hs ‘$HSFILE :: alias hs$HSFILE=’sudo hs ‘$HSFILE

    you can run it from any terminal window and it’ll prompt you for a root password before it runs, and no errors when you accidentally try and run it from a non admin shell. 🙂


  5. Johannes said:

    adding tab completion is a one-liner if you add the following to your ~/.profile:
    complete -W ‘$( ls /usr/local/share/hs | sed s/hosts.//)’ hs

  6. Mark said:

    I cant seem to get the switching working in Lion. Are the symlinks going to the correct location for Lion?

  7. It’s worth noting that as of Lion, /etc/hosts can not be a symlink. I’m not sure why… I’ve tried chowning and chomping the target file to no avail. Maybe there is a place on the system where it could be symlinked to, but I haven’t found it.

  8. Ben Hass said:


    I tried using your script on OSX lion, and it worked for a few days, but soon I started getting sandboxd errors in Console. My local development file would only be read if AirPort was turned off. I since switched to using GasMask (just editing my hosts file through that editor), but thought I’d let you know about this issue in case you want to modify the tutorial.


  9. Mathew said:

    OK To make this work in LION you need to do use a copy instead of a symlink as Lion will not follow a symlink anymore.

    Delete the test for real files Lines 32-36

    Change “sudo ln -f” to “sudo cp -f” in line 39 (line 39 before the other lines are deleted).

    You also do not need to do the steps to create the initial symlink (third item in step 1)

    Hope that helps.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: