1

I am trying to write a function in bash that checks if a given hostname is present in /etc/hosts. Comments and partial matches should not count. In other words, it should only return 0 if exactly the specified hostname was found. This is what I got so far:

check_host()
{
    AWK=$(awk '$1 ~ /^#/ { next } $2=="'$1'" {print $2}' /etc/hosts)
    if [ -n "$AWK" ]; then
        return 0
    else
        return 1
    fi
}

I would prefer to use awk or grep to get the solution.

The function worked on my smaller local file, but it somehow failed on bigger ones; I am unsure of the reason. What am I missing? How could I improve or simplify my function?

I've already checked the following answer, but it does not work as expected: https://stackoverflow.com/a/25277451/157762

2 Answers 2

2

You can use the getent command and pipe it to awk:

getent hosts | awk -v host="$HOSTNAME" '{for(i=1;i<=NF;i++){if($i==host){print $i;e=1}}}END{exit !e}'

awk splits the line using sequences of spaces as the (default) separator and checks if it exactly matches the hostname. If found it prints the hostname and exits with 0, otherwise it outputs nothing and exits with 1.

getent has the advantage that it displays the local host information which is in effect on the system rather than parsing /etc/hosts. While this might be preferred for a lot of use cases, I can also imagine of use cases where it is indeed required to parse /etc/hosts. In that cases I would suggest to use a real parser for that, like mentioned here

Former answer (wrong)

You can use the getent command:

getent hosts | grep -wF HOSTNAME

However, this depends on the hosts setting in /etc/nsswitch.conf, but it should work with the default configuration that ships with all Linux distros I'm aware of.

Wrong because: -w tells grep that the pattern should be enclosed by word boundaries, I was using it to make sure that foo-bar would not match the pattern foo. Unfortunately the hyphen is a word boundary!! (facepalm)

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks, that is definitely valid, but for those reasons I also want a solution involving either grep or awk or both.
Try to add hostname and hostname-01 to /etc/hosts. getent hosts | grep -wF hostname returns both :(
Oh, I see. You are right. -w tells grep that the pattern should be enclosed by word boundaries. Unfortunately the hyphen is a word boundary.. Let me elaborate the command..
This will always exit 1, even if exit once after host is found, END block will be evaluated, try this printf "1\n2\n" | awk '$1==1{exit 0}END{exit 12}'; echo $? and exit code will be 12
Instead of awk -ve=1 '...{e=0}...END{exit e} consider awk '...{e=1}...END{exit !e}. Btw not having a space between -v and the variable being initialized makes the script unnecessarily gawk-specific.
|
1

You can use a function like this:

check_host() {
    [[ -n $(awk -v host="${1//./\\\\.}" '!/^[[:blank:]]*#/ { $1="" }
            $0 ~ "[[:blank:]]+" host "([[:blank:]]|$)"' /etc/hosts) ]]
}

Testing:

check_host localhost; echo $?
0

check_host foobar; echo $?
1

7 Comments

I think you missed &&
You can add multiple hosts per IP in /etc/hosts. $2 would not work. You need to iterate over the columns
@anubhava What if a line contains 192.168.0.10 foo # was bar before? When search for bar, your command returns a match. I mean, comments might appear at the end of the line.
As per the question OP was trying to check for comments only at beginning so that's what I also captured in my answer
@anubhava Another thing: host will get handled as a regex, you need to sanitize regex special chars before using it. Check this for example: awk -vhost='foo.bar' '$1 ~ host' <<< 'foo-bar' - which returns a wrong match (and is a common use case).. I know, it is a pain in the a** :D
|

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.