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?

2
  • When the name exists, the IP is in the 4th field. Also, host can print multiple lines of output. Commented Jun 3, 2020 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" Commented Jun 4, 2020 at 7:10

4 Answers 4

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
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks a lot, i want cut to print just the 5th field of the file though which is the hostname.
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.
Unless you're talking about www.google.com has IPv6 address 2607:f8b0:4006:810::2004 the IPv6 address is in the 5th field
Its kinda like that: ip address.in-addr.arpa domain name pointer hostname.
Of course. I should have realized that you're doing reverse DNS because it's $ip not $hostname
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
-

3 Comments

have searched for host exit status but didn't find anything - do you know meanings (besides usual 0,1)?
@alecxs looks like it's just success --> 1, failure --> 0. That's not that uncommon with utils
@alecxs you didn't get the memo? Today is backwards day :)
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

2 Comments

you could check for host non-zero (1-255) exit status maybe $? returns 3 (and host -4 will skip IPv6)
@alecxs thank you for your input. In some bash versions like on debian host -4 and -6 is not supported
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/

5 Comments

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éaGris thank you for you input, can you give me a example of a turkish ipv6 with turkish locales ?
[0-9a-fA-F]{1,4} will match with bäd and it is not a valid hexadecimal number.
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éaGris you could answer here too (may helpful to others) stackoverflow.com/a/37355379

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.