2

This question already has an answer here:

I have crafted a Bash tool that runs on a server. This tool will block certain IP addresses for a certain time range (i.e. from 5 A.M. to 3:30 P.M.).

As of currently, the tool works fine, but I have to input IP addresses to certain websites manually into a text file and have the tool pull the IP address based on the nth line using the "head" and "tail" commands. I don't want to do this as I believe a single ping will be much more lightweight and portable. So if I do a ping for Google:

ping google.com -c 1 -s 16

The output will be:

Ubuntu@yokai:~# ping google.com -c 1 -s 16
PING google.com (173.194.66.138) 16(44) bytes of data.
24 bytes from qo-in-f138.1e100.net (173.194.66.138): icmp_seq=1 ttl=37 time=46.7 ms

--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 46.748/46.748/46.748/0.000 ms

And the command I have narrowed this output down with is:

ping google.com -c 1 -s 16 | grep -o '([^ ]*' | tr -d '(44):\n'

Which gives me an output of:

173.19.66.113173.19.66.113ubuntu@yokai

As you can see, there is a duplicate of the same IP address. How can I remove the duplicate with sed so that I can store the single IP address into a variable and run the script as a cronjob, or am I on a better track using tr?

(EDIT)

I already know/knew how to resolve IP address from a host name or domain. That is not what I am asking here. This question is specifically about managing ping output using sed in order to keep the tool I have created more portable as ping comes default with almost any and all linux distros.

(UPDATE) Since some marked this question a duplicate of some other bullshit question that has nothing to do with this one, I will make it clear enough that retards with English comprehension troubles can understand:

How to parse the IP ADDRESS "ONLY" from ping OUTPUT when using ping on a domain name.

This is NOT asking to resolve a domain name and therefore is NOT A DUPLICATE!!!

(LATEST UPDATE) I have, since asking this question, learned proper POSIX regex to do what I needed and I need to make it clear that I was originally asking about the regular expressions for sed that would print a single instance of an IP from ping output. I have since refined my methods and do not use any of the answers here but I thank everyone for their attempts with helping here. I am now using a timer script that I created to configure iptables at certain times to block certain domain name resolutions. Again, thank you to everyone that tried to help.

marked as duplicate by Julie Pelletier, G-Man, Archemar, Networker, Bananguin Sep 5 '16 at 10:00

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Editing the question to resolve the possible duplicate. – Yokai Sep 5 '16 at 6:01
  • 1
    Everything about what you are doing gives me a headache. sed operates on each line, whereas ping generates multiple lines of output, of which many contain the string you are looking for. This makes sed not the optimal choice for your problem. If you just want a portable way to resolve a host name, you should look at the link provided by @cutrightjm . If you want to extract IP Adresses from sings you can look here. – Bananguin Sep 5 '16 at 9:59
  • 1
    You clearly state that your goal is getting rid of your manually maintained list of IP addresses. For your approach you provide/use are host names as input. Even your question title says you want to "pull" IP addresses. Everything in the answer(s) you marked as correct can be found in the referenced question, INCLUDING A PING/SED CONSTRUCT. You could have found your answer there; ready for copy/paste. Your question is 100% redundant. This is what we call a duplicate. – Bananguin Sep 6 '16 at 7:32
  • My search, before asking, was: "pull ip address from ping output" and nothing about constructs with sed and ping shown in the suggested answered questions. Either the search results engine is faulty, or it doesn't know how to reference keywords in a search. Regardless, the search suggested posts shown me nothing of use. It is not my fault. Tell it to the maintainers of the site. – Yokai Sep 6 '16 at 10:20
  • If you wish to have proof of what I am telling you, here is a screenshot of my search results: dropbox.com/s/45asbz1rdcs8zma/proof-of-faulty-results.png?dl=0 – Yokai Sep 6 '16 at 10:30
10

ping is for checking whether a host is up or down based on ICMP response, it is never the right tool for only resolving IP address, there are dedicated tools for that.

You should look at dig, host, nslookup -- whatever suites you the best.

Here's a dig output:

% dig +short google.com
123.108.243.57
123.108.243.51
123.108.243.54
123.108.243.48
123.108.243.60
123.108.243.52
123.108.243.56
123.108.243.55
123.108.243.61
123.108.243.58
123.108.243.49
123.108.243.50
123.108.243.59
123.108.243.47
123.108.243.53

As a side note, in Linux, if you want to query by the NSSwitch (Name Service Switch) i.e. /etc/nsswitch, then use the getent command with hosts (or ahosts) database e.g.:

getent hosts google.com

In my computer, i have:

hosts: files mdns4 dns

in /etc/nsswitch.conf, so getent hosts will query in sequence and use gethostbyaddr(3) or gethostbyname(3) based on name and ahosts will use getaddrinfo(3).

In essence, with my configuration, this will first check /etc/hosts, then mDNS and at last DNS.


If you insist on using ping and sed, you can do:

% ping -c1 google.com | sed -nE 's/^PING[^(]+\(([^)]+)\).*/\1/p'
123.108.243.56
  • Very nice! This will avoid all of the pipes I was testing out as well. I completely forgot about dig! Very helpful Sir! – Yokai Sep 5 '16 at 3:16
  • 1
    ping and grep... ping ... | grep -oP 'PING.*?\(\K[^)]+' – Sundeep Sep 5 '16 at 3:23
  • @spasic Same thing, will need PCRE as an addition. – heemayl Sep 5 '16 at 3:24
  • dig, host, and nslookup always use the resolver (i.e. DNS). Other programs may also use the resolver, or they might call gethostbyname(3) or getnameinfo(3), which can be configured to query other sources in addition to DNS (such as /etc/hosts, NIS, etc.). That's of course system-dependent, and to the best of my knowledge there is no standard way to query gethostbyname(3) short of writing a program. However most implementations of ping(8) do call gethostbyname(3), and that's why people use ping(8) to resolve addresses. They aren't completely in the wrong. :) – Satō Katsura Sep 5 '16 at 5:38
  • @SatoKatsura getent hosts? – heemayl Sep 5 '16 at 5:41
4

Browsing Google I found a link to another unix.SE post that mentions getent - I didn't even know this program existed.

You can use getent like dig to resolve an IP to a hostname - and my system had getent installed by default, but not dig. If you want ipv6 hosts, change ahostsv4 to ahostsv6.

getent ahostsv4 google.com | awk '{print $1}' | head -1

I added this answer because I'm bad at regexes / sed and wouldn't have been able to come up with @heemayl's answer.

  • getent ahost4 google.com - Unknown database: ahost4. – Satō Katsura Sep 5 '16 at 5:52
  • @SatoKatsura it's ahosts, not ahost – cutrightjm Sep 5 '16 at 5:56
  • 1
    Same result with getent ahosts google.com. It's OpenBSD, not Linux. :) – Satō Katsura Sep 5 '16 at 5:57
  • With dig not being on your system by default, this is the reason I wanted to keep using ping since ping is installed on most all linux systems by default. Would make it more portable. Thanks for putting in the word on the getent tool bro. – Yokai Sep 5 '16 at 5:58
  • @SatoKatsura The result may not apply for OpenBSD - I have no idea, I've never used it. I'm running Debian on the box I tested this command on – cutrightjm Sep 5 '16 at 6:17
2

One thing to note is that, as you see in @heemayl's dig output, some sites may have more than one IP address. You'll likely need a DNS lookup to get them all, as ping will just use the first address it gets. Same for anything else that mainly wants to connect, and not specifically list the addresses.

(Also, in the case of something like google, you'll get different IP addresses depending on where you are based. Might not be a problem here, but good to note.)

Another thing, about the command you used. This: tr -d '(44):\n' removes all copies of the characters (, 4, ), : and \n from the input. tr always only looks at single characters, not strings. Looking at the output you got, you'll see that a 4 has gone missing from the middle of the IP address. Use some other tool like sed to work with strings.

Just for the sake of showing different colours for the bike shed, here's another simple one, with GNU grep:

$ ping google.com -c1 | head -1 | grep -Eo '[0-9.]{4,}'
172.217.22.174
  • I am already aware that some domain names give out more than one IP address. That isn't an issue. The command I gave was an example of my researching on my own. It has since been corrected in my tool. There is no reason to point out the obvious. – Yokai Sep 6 '16 at 5:20
  • I am also aware that the (44) that was printed to standard output was removed. That was intentional. There was no 4 removed from my ping output from an IP address as the IP addresses I connect to do not have a 4 in them. The IP is 173.19.66.113. This doesn't have a 4 in it. – Yokai Sep 6 '16 at 5:25
  • @Yokai, Your stated purpose was to block certain sites based on their IP addresses. In that case one wants to make sure to get all of the IP addresses, since otherwise they'll only some connections; a simple reload might get another address and connect. That makes ping hard to use for name resolving in this case. This may be obvious to you, but it's not obvious from the question as written. Any future readers might not think about it immediately, so it's worth pointing out. – ilkkachu Sep 6 '16 at 6:57
  • @Yokai, also, in your example, the address does have a 4 in it, and it's duly removed by tr. The output from ping starts PING google.com (173.194.66.138) 16(44) bytes of data. Of course in your other snippet, the address ends in .113, not .138, so clearly a different address was picked this time. While the addresses of any given hostname don't need to have any relation with each other, I think it's far more likely for the addresses of google.com to only differ in the last octet, than for them to differ in the second octet (with the third remaining the same, even). – ilkkachu Sep 6 '16 at 7:07
  • @Yokai, also: the address and matching DNS name in your example: 173.194.66.138 -> qo-in-f138.1e100.net, the same with .113: 173.194.66.113 -> qo-in-f113.1e100.net. The same without the 4 is in a different domain entirely: 173.19.66.113 -> 173-19-66-113.client.mchsi.com. (that looks like a name for a dynamically assigned DHCP address.) Even if your addresses don't have any fours in them, it's not very robust to assume they never will, since the point of name resolving is that you don't need to care if the addresses change. – ilkkachu Sep 6 '16 at 7:13

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