Skip to content

Instantly share code, notes, and snippets.

@mikeflynn
Created December 13, 2012 19:04
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save mikeflynn/4278796 to your computer and use it in GitHub Desktop.
Save mikeflynn/4278796 to your computer and use it in GitHub Desktop.
An /etc/hosts manager bash script (v1.1) -- Added import and export commands!
#!/bin/bash
HOSTSFILE="/etc/hosts"
BAKFILE="$HOSTSFILE.bak"
DOMAINREGEX="^[a-zA-Z0-9]{1}[a-zA-Z0-9\.\-]+$"
IPREGEX="^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
URLREGEX="^https?:\/\/[a-zA-Z0-9]{1}[a-zA-Z0-9\/\.\-]+$"
backup()
{
echo "Backup created at $BAKFILE";
cat $HOSTSFILE > $BAKFILE
}
usage()
{
echo "Usage:"
echo "$0 add [host] [ip]"
echo "$0 remove [host]"
echo "$0 update [host] [ip]"
echo "$0 check [host]"
echo "$0 rollback (reverts the last change)"
echo "$0 import [file or url] [--append] (replaces or appends the host file with the new one)"
echo
}
isroot()
{
# Check for root user
if [ $(whoami) != "root" ]; then
echo "$0 must be run as root... Aborting."; echo;
exit 192
fi
}
# Check that we're in a BASH shell
if test -z "$BASH" ; then
echo "update-hosts.sh must be run in the BASH shell... Aborting."; echo;
exit 192
fi
case $1 in
add)
isroot
# Do we have enough arguments?
if [ ! $# == 3 ]; then
echo "Missing arguments: $0 add [host] [ip]"; echo;
exit 192
fi
# Does the host look valid?
if [[ ! $2 =~ $DOMAINREGEX ]]; then
echo "Invalid hostname: $2"; echo;
exit 192
fi
# Does the IP look valid?
if [[ ! $3 =~ $IPREGEX ]]; then
echo "Invalid IP address: $3"; echo;
exit 192
fi
# Check to see if the host is already in the file
REGEX="$2$"
if [ $(cat $HOSTSFILE | grep '$REGEX' | wc -l | sed 's/^ *//g') != 0 ]; then
echo "The host $2 is already in the hosts file."; echo;
exit 192
fi
echo -e "$3\t$2" >> $HOSTSFILE
echo "Added $2"; echo
;;
check)
# Do we have enough arguments?
if [ ! $# == 2 ]; then
echo "Missing arguments: $0 check [host]"; echo
exit 192
fi
REGEX="${2}$";
if [ $(cat $HOSTSFILE | grep $REGEX | wc -l | sed 's/^ *//g') != 0 ];
then
cat $HOSTSFILE | grep $2
else
echo "The host $2 was not found in the host file."; echo;
fi
;;
remove)
# Do we have enough arguments?
if [ ! $# == 2 ]; then
echo "Missing arguments: $0 remove [host]"; echo
exit 192
fi
isroot
REGEX="$2$"
if [ $(cat $HOSTSFILE | grep $REGEX | wc -l | sed 's/^ *//g') = 0 ]; then
echo "The host $2 was not found in the host file."; echo;
exit 0;
fi
backup
cat $HOSTSFILE | sed -e "/$2$/ d" > tmp && mv tmp $HOSTSFILE
echo "$2 entry removed."; echo
;;
update)
# Do we have enough arguments?
if [ ! $# == 3 ]; then
echo "Missing arguments: $0 update [host] [ip]"; echo
exit 192
fi
isroot
# Does the IP look valid?
if [[ ! $3 =~ $IPREGEX ]]; then
echo "Invalid IP address: $3"; echo;
exit 192
fi
# Does the host look valid?
if [[ ! $2 =~ $DOMAINREGEX ]]; then
echo "Invalid hostname: $2"; echo;
exit 192
fi
backup
$0 remove $2
$0 add $2 $3
echo "$2 entry updated to $3"; echo
;;
import)
TEMPFILE="./hostsimport.$(date +%s).tmp"
APPEND=0
# Do we have enough arguments?
if [ ! $# -gt 1 ]; then
echo "Missing arguments: $0 import [file] {--append}"; echo
exit 192
fi
isroot
if [ ! -z $3 ]; then
if [ $3 == "--append" ]; then
APPEND=1
fi
fi
# Check the file type and fetch it if needed.
if [[ $2 =~ $URLREGEX ]]
then
echo "curl -s -o $TEMPFILE $2"
else
TEMPFILE=$2
fi
if [ -f $TEMPFILE ];
then
backup
IMPORTPREFIX="\n\n## IMPORTED FROM: $2\n\n";
if [ $APPEND == 0 ]
then
echo -e "$(head -n 11 $HOSTSFILE)$(echo $IMPORTPREFIX)$(cat $TEMPFILE)" > $HOSTSFILE
echo "$2 has been imported in to $HOSTSFILE.";
else
echo -e $IMPORTPREFIX >> $HOSTSFILE
cat $TEMPFILE >> $HOSTSFILE
echo "$2 has been appended on to $HOSTSFILE.";
fi
else
echo "Invalid import file."
fi
echo
;;
export)
# Do we have enough arguments?
if [ ! $# == 2 ]; then
echo "Missing arguments: $0 export [outfile]"; echo
exit 192
fi
isroot
cat $HOSTSFILE > $2
echo "Current $HOSTFILE saved to $2"
;;
rollback)
isroot
if [ -f $BAKFILE ]
then
cat $BAKFILE > $HOSTSFILE
rm $BAKFILE
echo "Rollback complete."; echo
else
echo "No backup file found!"; echo
fi
;;
-h)
usage
;;
*)
echo "Missing command. Type $0 -h for usage."; echo
;;
esac
exit 0
@denislutz
Copy link

Thank you! Started using it!

@nubot-nudt
Copy link

Thank you very much. This is really helpful.

@AWSadmin
Copy link

AWSadmin commented Apr 6, 2016

Thank you. Just what I needed.
Apparently, there is a dependency on Bash 3.2. Had to upgrade bash 2.0 on the server :)

@AWSadmin
Copy link

Hi Mike,

Just found an issue with the script.
I've scheduled your script in cron:
*/15 * * * * root /usr/local/bin/etchosts.sh update ecc606-b dig +short a hostname1.xyz.com

Despite using update command, after couple of days my /etc/hosts file is full of identical records like:

54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.194.xxx.xxx  ecc606-b
54.171.yyy.yyy   ecc606-b
54.171.yyy.yyy   ecc606-b
54.171.yyy.yyy   ecc606-b
54.171.yyy.yyy   ecc606-b
54.171.yyy.yyy   ecc606-b
54.171.yyy.yyy   ecc606-b

I thought update should update the record, but not add a new one into the /etc/hosts file. Could you check please?

Dmitry

@russellpierce
Copy link

russellpierce commented Jul 24, 2017

In playing around with this script I noticed that (at least for remove on OSX) the suffix of the hostname is matched. So, if you have bobworkstation and tomworkstation and remove tomworkstation, then you also lose the host entry for bobworkstation.

@ugcasa
Copy link

ugcasa commented Aug 24, 2019

very useful, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment