1

Till now, my network scripts used hostname -i, but after a recent update, the command started throwing an error: hostname: gethostbyname: Unknown host.

Now I don't know... should I be looking into a new command like ip? Or is this a common issue? I can't seem to find it mentioned anywhere. I would use ip, but I can't figure out a way, to display two IP's at the same time. For example when both of my interfaces are connected (eth and wlp).

Any suggestions?

2
  • Even a single interface can have a virtually unlimited number of IP addresses. You’ll just need to adapt whatever you’re doing to that fact. Perhaps some more context might help better answer the question, so tell us your ultimate goal.
    – Daniel B
    Dec 12, 2016 at 18:46
  • @DanielB, well, I just need to write out a single line with IPs separated by spaces, either to use for my i3Bar (display current IP), or other scripts that are based on Bash For loops.
    – niraami
    Dec 12, 2016 at 20:03

2 Answers 2

1

Same thing happened to me today. I checked/checksummed that /usr/bin/hostname file hasn't changed recently.

I grepped the strace output for opened files (excluding "No Such Files" in alternative $PATH's):

$ strace hostname -i |& grep open | grep -v "No such file"
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 3
open("/usr/lib/libnss_mymachines.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_resolve.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4

One-by-one inspection and comparison with the incremental backups for the last few days showed that /etc/nsswitch.conf changed from its previous version as of Sep 30, 2015, on Dec 10, 2016.

A side-by-side diff shows the differences (left side previous and restored, right side latest and backed-up):

$ diff -y /etc/nsswitch.conf /etc/nsswitch.conf.bck | grep \|
passwd: files                                                 | passwd: compat mymachines systemd
group: files                                                  | group: compat mymachines systemd
shadow: files                                                 | shadow: compat
hosts: files dns myhostname                                   | hosts: files mymachines resolve [!UNAVAIL=return] dns myhostn

Restoring the previous /etc/nsswitch.conf solves the problem and "hostname -i" returns the IPs given by interfaces as usual. You should backup the latest one just in case.

Update: After the bug I filed (https://bugs.archlinux.org/task/52133), systemd package maintainer Dave Reisner pointed out that the problem only occurs when the system-resolved daemon does not work. I checked and it is correct. In order for the new /etc/nsswitch.conf to work:

systemctl enable systemd-resolved

is needed.

According to the "top" output this adds a resident size of around 4m. Alternatively, one can go on with the previous line without systemd-resolved.

4
  • Didn't restore it, just replaced the hosts: line and it worked, quick fix to bug (is it actually a bug?) that will hopefully get resolved soon. Thanks for the in depth analysis though, imaginary +1 for the effort (can't vote yet).
    – niraami
    Dec 12, 2016 at 21:55
  • You're welcome, my pleasure. I see that, other libraries in the stderr of strace hasn't also changed recently.
    – S.C
    Dec 12, 2016 at 22:18
  • However, pkgfile shows that nsswitch.conf is a part of systemd package and it was updated on the 9th of December (archlinux.org/packages/core/x86_64/systemd). It is better to file a bug ticket.
    – S.C
    Dec 12, 2016 at 22:20
  • This change in package was requested by task 51709 (bugs.archlinux.org/task/51709) and I filed a bug by task 52133 (bugs.archlinux.org/task/52133)
    – S.C
    Dec 12, 2016 at 22:39
0

If you plan to use ip, this is an example on how to get the correct ip address from this ip address show output:

$ ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:92:55:ff brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname ens5
    inet 192.168.124.29/24 metric 1024 brd 192.168.124.255 scope global dynamic eth0
       valid_lft 2742sec preferred_lft 2742sec
    inet6 fe80::5054:ff:fe92:55ff/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

Run:

ip a s dev eth0 | grep "inet " | grep -oE "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}" | head -1


Explanation:

  • ip a s dev eth0, which is the same as ip address show dev eth0, will output only information regarding device eth0. This is the device with the ip address that I need. Output is:
$ ip a s dev eth0

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:92:55:ff brd ff:ff:ff:ff:ff:ff
    altname enp0s5
    altname ens5
    inet 192.168.124.29/24 metric 1024 brd 192.168.124.255 scope global dynamic eth0
       valid_lft 2331sec preferred_lft 2331sec
    inet6 fe80::5054:ff:fe92:55ff/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

  • grep "inet " will match the line containing inet . The whitespace is quite important to avoid matching inet6 (you can also run ip -4 a s dev eth0). Output:
$ ip a s dev eth0 | grep "inet "

    inet 192.168.124.29/24 metric 1024 brd 192.168.124.255 scope global dynamic eth0

  • grep -oE "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}" is a REGEX that will match ONLY strings that have: "(1 to 3 digits)DOT(1 to 3 digits)DOT(1 to 3 digits)DOT(1 to 3 digits)".
    The regex pattern can also be stored in a variable and used later:
    REGEX="[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}", Output:
$ REGEX="[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}"
$ ip a s dev eth0 | grep "inet " | grep -oE $REGEX

192.168.124.29
192.168.124.255

  • head -1 to output only the first match (the first line), which is the one just after init (the second one is the broadcast address). Output:
$ REGEX="[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}"
$ ip a s dev eth0 | grep "inet " | grep -oE $REGEX | head -1

192.168.124.29


If you have access to hostname -I, just use this:

hostname -I | cut -d' ' -f1
2
  • Sounds like it would be easier to parse the JSON output (ip --json -4 a s dev eno1 | jq -r '.[].addr_info[].local') than to worry about correctly regexing an IPv4 address... Nov 21, 2023 at 10:36
  • The more options to achieve this, the merrier, in my opinion. One can then simply use the one that fits better. But yes, the command you pointed out is a better solution :)
    – manero
    Nov 21, 2023 at 11:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .