Вопрос или проблема
Я хотел бы напечатать конкретную информацию о сетевой конфигурации для различных интерфейсов на всех серверах, которыми я управляю:
- имя интерфейса
- ipv4 адрес интерфейса
- аппаратный mac адрес интерфейса
- …
К сожалению, простой ip -o addr show
не позволяет легко распарсить его вывод с помощью awk
из-за разрывов строк.
Можно ли сделать так, чтобы ip addr show
выводило точно одну строку на интерфейс?
Или можно ли добиться такого же результата с помощью awk
и/или sed
? Это выходит за пределы моих знаний о этих двух командах, так как строки должны быть сконкатенированы дерево за деревом…
Просто используйте флаг –brief.
ip --brief address show
Новые версии ip
могут выводить данные в формате JSON с опцией -j
, которые затем можно обработать с помощью фильтра, например jq
. Например, вот как можно вывести IPv4 адрес на интерфейсе eth0
:
$ ip -j addr show dev eth0 | jq -r '.[0].addr_info | map(select(.family == "inet"))[0].local'
192.168.0.1
Или чтобы получить список всех IPv4 адресов на компьютере, по одному в строке:
ip -j addr show | jq -r 'map(.addr_info) | map(map(select(.family == "inet").local)) | flatten | .[]'
127.0.0.1
192.168.0.1
172.19.0.1
172.17.0.1
172.18.0.1
Удалите select(...)
, чтобы включить IPv6, например. Возможно много других вариаций.
Существует ip -o addr show
, но он выводит меньше информации.
Вот способ преобразовать вывод ip addr show
в одну строку на интерфейс. Напечатать новую строку перед началом каждого интерфейса, кроме первой строки; затем напечатать содержимое строки; напечатать новую строку в конце файла.
ip addr show |
awk '/^[^ ]/ && NR!=1 {print ""}
{printf "%s", $0}
END {print ""}'
sed -nE '/^[0-9]/! {H;$!d} # аккумулировать завершающие строки
x # обмен новой ведущей строки на накопленный пучок
s/[^ ]* ([^ ]*).* link\/[^ ]* ([^ ]*).* inet ([^ ]*).*/\1\t\3\t\2/p'
и замена довольно прямолинейная, идентифицирует и красиво выводит 2-е слово, слово после link/anything
, слово после inet
Этот скрипт gawk
распарсит ip addr show
и предоставит запрошенную информацию. Несколько IPv4 адресов соединены запятой
ip a | awk 'function outline() {if (link>"") {printf "%s %s %s\n", iface, inets, link}} $0 ~ /^[1-9]/ {outline(); iface=substr($2, 1, index($2,":")-1); inets=""; link=""} $1 == "link/ether" {link=$2} $1 == "inet" {inet=substr($2, 1, index($2,"https://unix.stackexchange.com/")-1); if (inets>"") inets=inets ","; inets=inets inet} END {outline()}'
Выделение для чтения:
ip addr show |
awk '
# Функция вывода для форматирования результатов (если есть)
function outline() {
if (link>"") {printf "%s %s %s\n", iface, inets, link}
}
# Секция интерфейса начинается здесь
$0 ~ /^[1-9]/ {
outline(); # Вывести все, что раньше коллекционировали
iface=substr($2, 1, index($2,":")-1); # Захватить имя интерфейса
inets=""; # Очистить список адресов
link="" # и MAC тоже
}
# Захватить MAC
$1 == "link/ether" {
link=$2
}
# Захватить IPv4 адрес. Конкатенировать с предыдущими с запятой
$1 == "inet" {
inet=substr($2, 1, index($2,"https://unix.stackexchange.com/")-1); # Отбросить /nn маску подсети
if (inets>"") inets=inets ","; # Добавить к существующему списку запятую
inets=inets inet # Добавить этот IPv4
}
# Ввод обработан
END {
outline() # Вывести оставшуюся коллекцию
}
'
Пример вывода
eth0 10.0.2.15 08:00:27:0f:db:b3
eth1 192.168.56.101 08:00:27:33:04:26
на debian:
man ip
...
-o, -oneline
выводит каждую запись на одной строке, заменяя переносы строк на символ '\'. Это удобно, когда нужно посчитать записи с помощью wc(1) или grep(1) в выводе.
[email protected] так как я ранее неправильно истолковал вопрос.
Попробуйте это:
ip addr show|xargs|sed 's/ \([0-9]*: \)/\n\1/g'
Каждая запись адаптера начинается с [0-9]*:
, что может быть вашим разделителем:
root@jprst0202:~# ip addr show
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
2: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 10.7.11.1/24 brd 10.7.11.255 scope global tun0
valid_lft forever preferred_lft forever
4: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 10.7.5.1/24 brd 10.7.5.255 scope global tun1
valid_lft forever preferred_lft forever
...
Итак:
- xargs – всё на одну строку
- sed… – добавляется новая строка перед каждым пробелом,числом (или множеством), двоеточием и снова пробел паттерн
Результат:
root@jprst0202:~# ip addr show|xargs|sed 's/ \([0-9]*: \)/\n\1/g'
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
2: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.11.1/24 brd 10.7.11.255 scope global tun0 valid_lft forever preferred_lft forever
4: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.5.1/24 brd 10.7.5.255 scope global tun1 valid_lft forever preferred_lft forever
5: tun2: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.7.1/24 brd 10.7.7.255 scope global tun2 valid_lft forever preferred_lft forever
...
Используйте команду ip -br a
❯ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
eno1 UP fe80::1e1b:dff:fe9c:59be/64
eno2 DOWN
enp193s0f0 UP fe80::92e2:baff:fe18:9e64/64
enp193s0f1 UP
br-mgmt UP 10.1.1.11/24
lxcbr0 DOWN 10.100.0.1/24
virbr0 DOWN 192.168.122.1/24
virbr1 UP 192.168.121.1/24
vnet0 UNKNOWN fe80::fc54:ff:fe68:63cb/64
vnet1 UNKNOWN fe80::fc54:ff:fe41:8608/64
docker0 DOWN 172.17.0.1/16 2001:db8:1::1/64 fe80::42:92ff:fe5d:ea35/64 fe80::1/64
br-5437536a1d09 DOWN 10.10.0.1/16
Ответ или решение
Когда речь заходит о вычислении конфигураций сетевых интерфейсов на ваших серверах, инструментарий, такой как ip addr
, играет ключевую роль. Понимание и умение интерпретировать его вывод — это основная задача для IT специалистов, поскольку она позволяет глубже оценить сетевые параметры и выявить возможные проблемы.
Теория
Первое, что нужно понять — это предназначение команды ip addr
. Этот инструмент используется для отображения или манипуляции с IP-адресами устройств в сети. Он предоставляет исчерпывающую информацию о каждом сетевом интерфейсе на вашем сервере, включая имя интерфейса, его IP-адрес (как IPv4, так и IPv6), MAC-адрес и другие атрибуты.
Пример
Рассмотрим типичную задачу: вам необходимо отобразить информацию о сетевых интерфейсах в формате одной строки на интерфейс. Это позволит более эффективно обрабатывать данные с помощью других инструментов, таких как awk
или sed
, применяя их для дальнейшего анализа или обработки.
Реализация
Самый простой способ получить краткий вывод с каждой строкой, представляющей отдельный интерфейс, — это использовать флаг -o
(или --oneline
) с ip addr
. Это обеспечивает вывод, где каждая запись представлена в одной строке:
ip -o addr show
Однако для получения более комплексного вывода и учитывая, что данная команда может быть менее информативной в плане глубокого анализа, возможно рассмотрение следующих альтернатив:
-
Использование флага
-j
для вывода в формате JSON
Новые версииip
поддерживают вывод в формате JSON при использовании флага-j
. Это позволяет легко обрабатывать данные с помощьюjq
, который предоставляет гибкость при извлечении нужной информации:ip -j addr show | jq -r '.[] | "\(.ifname) \(.addr_info[]? | select(.family=="inet") | .local) \(.link_info?.address)"'
В этом примере вы извлекаете имя интерфейса, IPv4-адрес и MAC-адрес для каждого интерфейса.
-
Использование
awk
для преобразования вывода
В случаях, когда необходимо более глубоко обработать выводip addr
, вы можете использоватьawk
:ip addr show | awk ' function output() {if (iface != "") {printf "%s %s %s\n", iface, inet, mac}} /^[0-9]+:/ {output(); iface=$2; inet=""; mac=""} /link\/ether/ {mac=$2} /inet / {inet=inet $2 " "} END {output()}'
Этот скрипт захватывает имя интерфейса, его MAC-адрес и IPv4-адрес.
-
Обработка вывода с помощью
sed
Альтернативно,sed
может быть использован для предварительной обработки и выравнивания строк:ip addr show | sed -nE '/^[0-9]/!{H;$!d}; x; s/^ //; s/^([0-9]+: )([a-zA-Z0-9]+):.* link\/[^ ]+ ([^ ]+).* inet ([^ ]+).*/\2 \4 \3/p'
Этот скрипт упрощает вывод, сохраняя ключевые элементы.
На практике, использование правильного инструмента и метода зависит от конкретных требований вашей задачи. Для более простых задач может быть достаточно использовать простые флаги команд, такие как -o
или -br
, но для более сложного анализа и интеграции лучше воспользоваться JSON
-выводом и jq
.
Заключение
В современной ИТ-среде важно уметь выбирать подходящие инструменты для анализа и управления системами. Способность адаптировать и обрабатывать вывод командных утилит, таких как ip addr
, с применением awk
, sed
или jq
, позволяет не просто следить за состоянием системы, но и активно управлять ею. Это навык, который значительно увеличивает производительность вашего ИТ-менеджмента и позволяет более стратегически подходить к вопросам сетевой архитектуры и безопасности.