1

I have two Linux machines. One is 4.4.12-99, one is 4.4.143. I just ran apt upgrade on them both.

I have an awk statement that contains a regex that works on 4.4.143, but fails on 4.4.12-99. I have searched for days and tried multiple different syntaxes to discover what can be wrong. awk is not failing or complaining, it's just not matching the word boundary. The scripts are the same on each machine and work fine except for this awk statement. On the one that is not working properly, I can cause it to match everything and provide that result.

ip=$(awk -v sUSER="$sUSER" 'BEGIN{gsub(/\./,"\\.",sUSER)}match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) && $0 ~ ("[^[:alnum:]]"sUSER"$") && $0 !~ /^$/ && $0 !~ /^#/{print $1}' /etc/hosts )

awk looks into the /etc/hosts file with a variable, $sUSER and tried to match a user to an associated IP address.

I cant figure out what I am doing wrong.

WesZ
  • 129
  • 1
  • 10
  • What is the sample file you are running this on? Give us a proper reproducible example to help us solve your problem – Inian Nov 21 '18 at 17:26
  • Hello, the sample file is the /etc/hosts file as shown at the end of the awk statement and once again, as is stated, this awk looks into the /etc/hosts file and extracts an IP address for a given username/hostname. – WesZ Nov 21 '18 at 17:57
  • 1
    @WesZ, your previous thread https://stackoverflow.com/questions/53353494/awk-matching-incorrect-hostname-in-etc-hosts how different it is please do let us know? That thread also you have not informed anyone about what happened, so please don't do so, take questions/problems one by one only – RavinderSingh13 Nov 21 '18 at 18:01
  • It says:Thanks. Hello. I wanted to post my final line of code that provides the correct output. I appreciate all of the help and guidance from those who responded. I wanted to post the final code in case someone in the future can find it useful. – WesZ Nov 21 '18 at 18:06
  • @WesZ, could you please do let us know if you have taken guidance from my or hek2mgl post. Both are based on different approaches but you should try it out both and let individual know about its status then/. – RavinderSingh13 Nov 21 '18 at 18:08
  • what is `4.4.12-99` ? that is a version number for ... what? – glenn jackman Nov 21 '18 at 19:52
  • RavinderSingh13 - I am working on the getent solution, but I would need to re-write a bunch of code to change things if I employed getent. But it is a possible solution to the issue. I would still prefer to find a way to use my awk statement ("[^[:alnum:]]"sUSER"$") to match the word boundary for the different versions. Apparently this awk statement is not portable to version 4.4.12-99 – WesZ Nov 22 '18 at 09:11
  • glenn - on a Linux command line type in uname -r and you will see the version. – WesZ Nov 22 '18 at 09:11
  • 1
    The kernel version has absolutely nothing to do with the verrsion of awk you're running. The kernel version is not a reliable way to identify a machine since you presumably perform updates now and then. – glenn jackman Nov 22 '18 at 14:03

2 Answers2

4

hek2mgl's answer is what you should use.

For your awk question, GNU awk regular expressions are documented here: https://www.gnu.org/software/gnulib/manual/html_node/gnu_002dawk-regular-expression-syntax.html

They use \< and \> as zero-width word boundary markers, so you can do

gawk -v sUSER="$sUSER" '
    BEGIN {
        gsub(/\./,"\\.",sUSER)
        ipv4Re = "^[0-9]+(\\.[0-9]+){3}$"
        sUserRe = "\\<" sUSER "\\>"
    }
    /^$/ || /^#/ {next}
    $1 ~ ipv4Re && $0 ~ sUserRe {print $1}
' /etc/hosts 

(whitespace is nice, you should try using it)


another approach is looping over the fields and using string equality which automatically encompasses word boundaries. This will work with gawk or mawk

awk -v sUSER="$sUSER" '
    !/^#/ {for (i=2; i<=NF; i++) if ($i == sUSER) print $1}
' /etc/hosts
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • Whitespace is your friend. Indentation solves a lot of debugging, lol – Paul Hodges Nov 21 '18 at 20:54
  • Hi Glenn - I used this code and my symptoms are the same. I have actually tried using this "awk" statement on 5 different machines, 4 of them it did not work and one it did work. It worked on the one that it always worked on. Do you think maybe there is a missing library or something? Maybe I should try and reinstall awk/mawk/gawk ?? I am really becoming perplexed with this. I have checked syslog and it reports nothing. – WesZ Nov 22 '18 at 09:47
  • I did note that the word boundaries are a GNU awk feature. GNU awk is not installed by default on some distributions: what awk are you running? And awk errors will not be syslogged. – glenn jackman Nov 22 '18 at 14:06
  • Well... it seems "Houston.....we have a problem...." The one that works fine is GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0) and the one that has problems is awk: not an option: --version awk -Wversion 2>/dev/null || awk --version mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan so what should I do? – WesZ Nov 22 '18 at 16:11
  • So is it gawk that needs to be installed to get the GNU stuff? – WesZ Nov 22 '18 at 16:18
  • OK.... I installed gawk on the one that was failing... GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0) and it works...…!!! – WesZ Nov 22 '18 at 16:22
  • Thanks Glenn…. installing gawk and your twice simplified code has been a life saver. I have another feature in my program that I will be using your awk loop code on as well. – WesZ Nov 23 '18 at 09:43
2

What you basically want to do is a local hostname lookup. There is a tool called getent for that purpose:

getent -s files hosts "${sUSER}" | cut -d' ' -f1

-s files tells getent to only use the local host databases (not DNS) which is /etc/hosts.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • Hello, this getent works, but can it be made to use a specified file? I looked on the man page, but it wasn't mentioned. I can use this, I would need to re-write some code to append the /etc/hosts file. If I can, I would like to use the awk code, although it is becoming a bit clunky... so maybe this is a better solution. Thanks. – WesZ Nov 21 '18 at 19:03
  • `getent hosts` is always using `/etc/hosts`. What you basically want to do is a local hostname lookup. `getent -s files` is made for that. – hek2mgl Nov 21 '18 at 19:13