Time to pull out your sys army knife and explore how to best use some of the tools available to system administrators out there!
Every system administrator knows that you should always use DNS names (e.g., myserver.mydomain.com) instead of IP addresses (e.g., 192.168.1.4). You should avoid ever using IP addresses in configuration files, URLs, or (heaven forbid!) hard coded into scripts or compiled programs. But every system administrator also knows that there are situations where you simply have to use an IP address (e.g., /etc/resolv.conf). And of course, some people just like to be ornery and use IP addresses even when a DNS name would work perfectly well.
Sooner or later, every system administrator encounters a situation where he needs to change the IP address of a system, or a few systems, or a few thousand systems.
So you’re changing the IP address of a system. You know that there might be things out there that contain that IP address — on the system itself, or perhaps on other systems. You don’t want to break said things. You need a quick and easy way to figure out what things use the current IP address of the system, so that you can change them when you change the IP address. What do you do?
The “grep” command is your friend.
One tool that every system administrator should be familiar with is “grep” and its accompanying versions “egrep” and “fgrep”. “Grep” is short for “get regular expression.” Basically a “regular expression” is a set of criteria for matching text. The “egrep” command is an “extended” grep, offering more text searching functionality and “fgrep” is a “fast” grep, which works more quickly but offers less functionality.
At its simplest, you can use grep to search for an IP address in file like this:
grep 'IP_address' file
$ grep '192.168.1.4' /etc/hosts 192.168.1.4 myserver myserver.mydomain.com
As you can see in the example above, we used grep to search for 192.168.12.4 in the /etc/hosts file and it found a line that defined 192.168.12.4 as the IP address for a server named myserver or myserver.mydomain.com.
Limiting your scope – periods are not what they appear.
The example above is not a particularly good one, though, because in grep a period is a “wild card” character. When you include a period in your regular expression, it doesn’t mean “look for a period.” It means “look for any character.”
So given the example above, you could just as easily end up with results that look like this:
$ grep '192.168.1.4' /etc/hosts 192.168.1.4 myserver myserver.mydomain.com 192.168.144.12 otherserver otherserver.mydomain.com
It’s obvious why the “myserver” line shows up, but if you’re not familiar with regular expressions you may wonder why on earth that second line showed up. The answer is simple: That period in your regular expression matches against any character. So it matches against the period in 192.168.1.4, but it also matches against the 4 in 192.168.144.12.
So how do you avoid this undesirable behavior? It’s simple: You just need to “escape” any periods in your regular expression by putting a backslash (\) in front of them. This tells grep that you don’t want the period to act as a wild card, but instead want to literally look for a period. Thus, your new search now looks like this:
$ grep '192\.168\.1\.4' /etc/hosts 192.168.1.4 myserver myserver.mydomain.com
Note that this time your search didn’t pick up the extra line.
Limiting your scope – word boundaries.
Unfortunately, we’re still not done refining our regular expression. Because a regular expression is matched against any part of the line, you still may end up getting results that you don’t want even after you’ve escaped your periods. For example:
$ grep '192\.168\.1\.4' /etc/hosts 192.168.1.4 myserver myserver.mydomain.com 192.168.1.40 workstation1 workstation1.mydomain.com 192.168.1.41 workstation2 workstation2.mydomain.com
Why do these extra lines show up? It’s simple, really: “192.168.1.4″ matches the first part of “192.168.1.40″ and “192.168.1.41,” so those lines both get picked up as well.
How do you avoid this? The best way is to use egrep (extended grep), which supports more powerful regular expressions. Egrep allows you to use “\b” to match against a word boundary.
Basically, the \b escape means “search for a word boundary here” (remember the mnemonic “\b is for boundary”). A word boundary is the beginning of a line, end of a line, any white space (tabs, spaces, etc.), or any punctuation mark. So if you put a \b in front of the IP address you’re looking for and another \b at the end of the IP address you’re looking for, you’ll eliminate the sort of partial match that happened above:
$ egrep '\b192\.168\.1\.4\b' /etc/hosts 192.168.1.4 myserver myserver.mydomain.com
Voila! Now those pesky extraneous entries no longer show up!
In all the examples above, I show grep/egrep searching for an IP address in just one file — /etc/hosts. Realistically, though, you’re far more likely to need to search all the files in an entire directory tree for the IP address. For instance, you might know that the IP address you’re changing could be in some configuration files somewhere in the /etc directory or one of its subdirectories. Or you might know that the IP address could be in the source code files associated with a particular application. Or you might even just know that the IP address could be used somewhere in some file on your machine — but it could be literally anywhere on the machine.
You can give the grep/egrep command a list of multiple files to check. For instance, you could search for your IP address in the /etc/hosts and /etc/resolv.conf file like this:
$ egrep '\b192\.168\.1\.4\b' /etc/hosts /etc/resolv.conf /etc/hosts:192.168.1.4 myserver myserver.mydomain.com /etc/resolv.conf:nameserver 192.168.1.4
You could even search all of the files in /etc like this:
$ egrep '\b192\.168\.1\.4\b' /etc/* /etc/hosts:192.168.1.4 myserver myserver.mydomain.com /etc/resolv.conf:nameserver 192.168.1.4
However, it’s important to note that that will only search for files in /etc. It won’t search for files in /etc/subdir, /etc/deeper/subdir, and so on.
The grep commands support a “-r” option to recursively search all the files in a given directory and all of its subdirectories. For example:
$ egrep -r '\b192\.168\.1\.1\b' /etc /etc/hosts:192.168.1.1 myrouter myrouter.mydomain.com /etc/ntp.conf:server 192.168.1.1 /etc/resolv.conf:nameserver 192.168.1.1 /etc/sysconfig/network:GATEWAY=192.168.1.1
One Caveat and Final Thoughts
There’s one important caveat to all of this: This post is about using GNU’s version of the grep tools, which are used by all Linux distros and are available for basically every other platform you can think of (I even use it on Windows). If you’re stuck on a system that only has old-school Unix grep commands installed, though, your mileage may vary. In particular, the -r option is not implemented on older Sys-V grep implementations.
And of course, this only shows how to search for a single IP address. When I get a chance, I’ll add another blog entry describing how to look for a list of IP addresses on a system, and how to search for anything that’s an IP address. I also intend to do a write-up on how you can do automatic search-and-replace of IP addresses using sed, another tool that should be part of every system administrator’s sys army knife.