Когда у вас много сетевых интерфейсов

Краткая версия:

ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1
  • Мы используем ip route и awk, чтобы определить имя нашего сетевого интерфейса по умолчанию.
  • Мы используем ip addr, чтобы получить сведения об IP для этого интерфейса.
  • Мы ищем только те строки, которые указывают на «inet».
  • Затем мы убеждаемся, что имеем дело только с одной строкой с помощью команды head. Для начала должна быть только одна строка «inet», но возможно, что их может быть и больше.
  • Мы используем awk для извлечения IP-адреса
  • Мы используем cut для удаления информации о подсети, если она присутствует.

Это немного многословно, но очень хорошо подходит для моего случая использования. Это можно сделать более кратко, приложив немного усилий. Примите это или воспользуйтесь другой техникой, которая соответствует вашим потребностям.

Мой пример использования

Обратите внимание: я собираюсь скрыть некоторые детали, поскольку они не имеют отношения к разговору. Цель здесь состоит в том, чтобы сосредоточиться на поиске IP-адреса хост-рабочей станции из сценария командной строки (в данном случае Bash), когда может присутствовать более одного сетевого интерфейса и жесткое кодирование имени интерфейса не является правильным ответом.

На моей рабочей станции Linux был запущен докер-контейнер, который предоставлял веб-службу через открытый порт. Я мог просто перейти к http://localhost:51234, чтобы получить доступ к этой службе. Самое интересное произошло, когда мне понадобился другой несвязанный контейнер докеров для доступа к той же службе. В этом случае у меня не было общей конфигурации сети Docker, на которую я мог бы опираться. Мне нужно было просто выполнить типичный HTTP-запрос, но «localhost» из ВНУТРИ этого контейнера означал контейнер, а не мой хост-компьютер. Исправление здесь состоит в том, чтобы просто использовать IP-адрес хоста, НО ... Ожидается, что созданный мной сценарий будет запускаться на нескольких компьютерах разработчика, каждый со своей собственной локальной версией веб-службы и собственными IP-адресами. Так что я не мог просто жестко закодировать свой IP. Просить разработчиков отредактировать конфигурацию тоже было неудобно (короткое время аренды DHCP-адреса, разные навыки разработчиков и т. Д.). Поэтому мне нужен был способ определить IP-адрес главного компьютера из сценария Bash, который запускал процессы.

Так что я его взломал.

Я начал с типичного ip addr. Здесь перечислены адреса IPv4 и IPv6 для всех сетевых интерфейсов. Если я предполагаю, что мой интерфейс по умолчанию - eth0, я мог бы сузить круг с помощью

ip addr show eth0

Но в списке нет ничего особенного, указывающего, какой интерфейс является «по умолчанию». Значение по умолчанию - это «предполагаемый» элемент знаний, основанный на том, как мы настраиваем компьютер, какое оборудование было доступно и т. Д. Поэтому я не могу использовать eth0 или wlan0, потому что нет гарантии, что интерфейс «по умолчанию» будет называться таким же на всех хост-компьютерах.

Ответом для меня было также использовать ip route. Здесь перечислены таблицы маршрутизации для рабочей станции. Важной частью здесь является строка, указывающая «по умолчанию через». Это наш интерфейс по умолчанию. Объединив это, мы можем сделать

ip route | awk '/default/ {print $5}'

Это дает нам ИМЯ интерфейса по умолчанию. ip route дает нам список записей маршрутизации, а команда awk находит запись с фразой «по умолчанию», а затем возвращает пятое поле из этой строки (разделенное пробелами). Интересно, что если вам нужен IP-адрес шлюза по умолчанию, вы можете просто изменить его на $3 вместо $5.

Объединение этого дает нам

ip addr show $(ip route | awk '/default/ {print $5}')

и это возвращает информацию об IP для нашего устройства по умолчанию. Чтобы еще больше урезать этот вывод, мы можем использовать awk, grep, head и cut, чтобы изолировать строку (строки) «inet». и извлеките ТОЛЬКО желаемый IP-адрес. Я описал, что делает каждая часть, выше, в «краткой версии».

Я использую это в своем скрипте так:

MYIP=$(ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1)

Если я затем «echo $ MYIP», я получу что-то вроде «192.168.1.55». И это значение, которое я затем могу передать в свой вторичный контейнер Docker (для этого я использовал флаг --env с командой docker run). Затем мой работающий контейнер может получить доступ к «http://192.168.1.55:51234» и получить ожидаемые результаты, если все остальное работает правильно.

В Интернете есть масса ответов, которые показывают, как получить свой IP-адрес. В моем случае большинство из них были слишком упрощенными или все же полагались на какие-то предполагаемые знания.

Спасибо банде IRC-канала #debian за помощь в поиске этого решения!