2

In the first if we want the hostname to appear, which is the 5th field from a file. Then if the IP we give to the host command does not exist, then the command returns message 3 (NXDOMAIN). The script should recognize if the command was "not found". In this case it will must simply print (-).

#!/bin/bash
ip="$1"

if [ "$ip" ] ; then
         host "$ip" | cut -d' ' -f5

 elif
         [[ "$ip" =~ "[3(NXDOMAIN)]$" ]] ; then
                echo "-"
fi

Do u have any solution on this exercise?

panos_lek
  • 21
  • 4
  • When the name exists, the IP is in the 4th field. Also, `host` can print multiple lines of output. – Barmar Jun 03 '20 at 21:25
  • Please be a bit more specific when asking a question: *What have you tried so far with a code example?* / *What do you expect?* / *What error do you get?* **For Help take a look at "[How to ask](//stackoverflow.com/help/how-to-ask)"** – Olli Jun 04 '20 at 07:10

4 Answers4

2

You're not testing the result of the host command, you're testing the value of the original $ip variable.

Save the output to a variable, test that variable, then either print the output or - depending on the test.

You don't need to do a regexp match, just match the exact string.

#!/bin/bash
ip="$1"

if [ "$ip" ] ; then
    result=$(host "$ip" | cut -d" " -f5)
    if [[ $result = "3(NXDOMAIN)" ]] ; then
        echo "-"
    else
        echo "$result"
    fi
fi
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks a lot, i want cut to print just the 5th field of the file though which is the hostname. – panos_lek Jun 03 '20 at 21:54
  • The output looks like: `www.google.com has address 172.217.10.228`. There's no 5th field when it succeeds. The hostname is in the 1st field, the address is in the 4th field. – Barmar Jun 03 '20 at 21:57
  • Unless you're talking about `www.google.com has IPv6 address 2607:f8b0:4006:810::2004` the IPv6 address is in the 5th field – Barmar Jun 03 '20 at 21:58
  • Its kinda like that: ip address.in-addr.arpa domain name pointer hostname. – panos_lek Jun 03 '20 at 22:00
  • Of course. I should have realized that you're doing reverse DNS because it's `$ip` not `$hostname` – Barmar Jun 03 '20 at 22:03
2

The answer is much simpler than you think, you don't need to do any matching. You can just use the return code from host

#!/bin/bash
ip="$1"

if domain=$(host "$1"); then
  echo "${domain##* }"
else
  echo "-"
fi

Proof of Concept

$ testHost(){ if domain=$(host "$1"); then echo "${domain##* }"; else echo "-"; fi }
$ testHost 172.217.6.46
sfo03s08-in-f14.1e100.net.
$ testHost 172.217.6.466
-
SiegeX
  • 135,741
  • 24
  • 144
  • 154
1
#!/bin/bash

if  [ -n "$1" ] && [[ $1 =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]] ;then

    res=$(host "$1" | cut -d' ' -f5)

    if [ "$res" != "3(NXDOMAIN)" ]; then
        echo "$res"
    else
        echo "-"
    fi

else
    echo "please enter a valid ip"
fi
  • you could check for `host` non-zero (1-255) exit status maybe `$?` returns 3 (and `host -4` will skip IPv6) – alecxs Jun 03 '20 at 22:20
  • 1
    @alecxs thank you for your input. In some bash versions like on debian host -4 and -6 is not supported –  Jun 03 '20 at 23:28
0

if you want to cover also ipv6 then I think this will cover it

#!/bin/bash

# ipv4
if [[ $1 =~ ^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])$ ]]; then

    res=`host "$1" | cut -d' ' -f5`

    if [ "$res" != "3(NXDOMAIN)" ]; then
        echo "$res"
    else
        # valid ipv4 IP but not connected
        echo "-"
    fi

# ipv6
elif [[ $1 =~ ^(([[:xdigit:]]{1,4}:){7,7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,7}:|([[:xdigit:]]{1,4}:){1,6}:[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,5}(:[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}:){1,4}(:[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}:){1,3}(:[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}:){1,2}(:[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}:((:[[:xdigit:]]{1,4}){1,6})|:((:[[:xdigit:]]{1,4}){1,7}|:)|fe80:(:[[:xdigit:]]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])|([[:xdigit:]]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]]))$ ]]; then

    res=`host "$1" | cut -d' ' -f5`

    if [ "$res" != "3(NXDOMAIN)" ]; then
        echo "1. $res"
    else
        # valid ipv6 IP but not connected
        echo "2. -"
    fi

else

    echo "Please enter a valid IP"
fi

Note: For some versions of bash the -4 and -6 options do not work.

Thanks to Léa Gris for pointing out the locales problem.

Inspired from https://helloacm.com/how-to-valid-ipv6-addresses-using-bash-and-regex/

  • 1
    Your regex is only valid within some locales and will fail on Turkish locale and others with very different alphabet and digits. Use `[[:xdigit:]]` for hexadecimal numbers and `[[:digit:]]` for decimal ones instead. – Léa Gris Jun 03 '20 at 22:38
  • @LéaGris thank you for you input, can you give me a example of a turkish ipv6 with turkish locales ? –  Jun 03 '20 at 22:40
  • 1
    `[0-9a-fA-F]{1,4}` will match with `bäd` and it is not a valid hexadecimal number. – Léa Gris Jun 03 '20 at 22:52
  • 1
    With Turkish Alphabet. `echo 'abçd' | grep -oE '[0-9a-fA-F]{1,4}'` wrongly match the `ç` witch is invalid for an hexadecimal number. Whereas matching with `echo 'abçd' | grep -oE '[[:xdigit:]]{1,4}'` you can see it is excluded from the match. – Léa Gris Jun 03 '20 at 23:02
  • @LéaGris you could answer here too (may helpful to others) https://stackoverflow.com/a/37355379 – alecxs Jun 04 '20 at 08:54