Редактирование /etc/network/interfaces в Debian средствами sed

В данное статье показаны примеры, как можно выполнять типичные действия над файлом конфигурации с помощью самого мощного потокового редактора.

В некоторых системных скриптах хотелось бы иметь возможность работы с конфигом сетевых интерфейсов.

Конфиг сетевых интерфейсов в Debian имеет примерно следующий вид:

$ cat /etc/network/interfaces
auto lo eth0 eth1
 
iface lo inet loopback
 
iface eth0 inet static
address 192.168.0.13
netmask 255.255.255.0
gateway 192.168.0.1
 
iface eth1 inet static
address 192.168.1.13
netmask 255.255.255.0
 
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M

Если работать только средствами sh (не говоря о языках более низкого уровня), то получается громоздкий, ресурсоемкий и сложный для написания и отладки код.

Далее предлагаю "простенькие" скрипты на sed'е, для типичных операций:



Удаление интерфейса.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса передается в параметре):

  1. #!/bin/sh
  2. [ -z "$1" ] && exit 1
  3. sed -n "/auto/s/$1 \?//;/iface $1/{:x;n;/iface/by;bx;};:y;p" /etc/network/interfaces

Более подробно на примере sed скрипта:

  1. #!/bin/sed -nf
  2.  
  3. #удаляю интерфейс из авто-поднимаемых (ищу строку начинающуюся со слова auto,
  4. #в ней ищу имя интерфейса (с пробелом или без) и вырезаю его):
  5. /auto/s/eth0 \?// #здесь конструкция ' \?' - означает: ноль или одно вхождение пробела
  6.  
  7. #### далее удаление интерфейса и его параметров ####
  8. /iface eth1/{ #если строка содержит имя интерфейса, выполняю группу действий:
  9. :x #метка
  10. n #беру на анализ следующую строку (тем самым пропуская вывод этой)
  11. /iface/by #если начался следующий интерфейс, значит достигнут конец этого интерфейса - перехожу на метку "y"
  12. bx #перехожу на метку "x" (для удаления остальных параметров этого интерфейса)
  13. }
  14. :y #метка
  15. p #вывожу текущую строку на печать

В результате работы sh скрипта:

$ ./del_iface eth0
auto lo eth1
 
iface lo inet loopback
 
iface eth1 inet static
address 192.168.1.13
netmask 255.255.255.0
 
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M

Еще вариант, хоть и более медленный и более сложный для понимания, но отображает другой подход:

  1. #!/bin/sed -f
  2. /^iface eth0/!b #прерываю анализ строки, пока не найду строку содержащей имя интерфейса
  3. s/iface //g #удаляю iface чтобы не мешался
  4. :x #метка
  5. /iface/!{ #если еще не дошел до следующего интерфейса, то
  6. N #прилепляю следующую строку к концу этой
  7. bx #перехожу на метку "x"
  8. }
  9. s/^eth1 .*iface/iface/ #удаляю все остатки про этот интерфейс


Удаление параметра интерфейса.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса и удаляемый параметр передаются параметрами):

  1. #!/bin/sh
  2. [ -z "$1" -o -z "$2" ] && exit 1
  3. sed "/iface $1/!b;:x;n;/$2/d;/iface/b;bx" /etc/network/interfaces

Более подробно на примере sed скрипта:

  1. #!/bin/sed -f
  2. /iface eth0/!b #пока не найду нужный интерфейс прерываю обработку
  3. :x #метка
  4. n #беру на анализ следующую строку
  5. /address/d #ищу параметр и в случае успеха удаляю строку
  6. /iface/b #если дошел до следующего интерфейса, значит такого параметра нет - прерываю обработку
  7. bx #перехожу на метку "x" (пока не найду нужный параметр)

Еще вариант, хоть и более медленный и более сложный для понимания, но отображает другой подход:

  1. #!/bin/sed -nf
  2. /iface eth0/{ #если строка содержит имя интерфейса, выполняю группу действий
  3. :x #метка
  4. p #вывожу текущую строку на печать
  5. n #беру на анализ следующую строку
  6. /address/b #если это строка с параметром, то прерываю анализ строки - тем самым не выводя на печать искомый параметр
  7. /iface/by #если начался следующий интерфейс, значит такого параметра нет - перехожу на метку "y"
  8. bx #перехожу на метку "x" (для удаления остальных параметров этого интерфейса)
  9. }
  10. :y #метка
  11. p #вывожу текущую строку на печать

Если скрипту передать имя интерфейса как eth, то удалится заданный параметр у всех интерфейсов eth (eth0, eth1 и т.д.). Пригодится, к примеру, для удаления шлюза по умолчанию (gateway).

В результате работы sh скрипта:

$ ./del_param_iface eth0 address
auto lo eth0 eth1
 
iface lo inet loopback
 
iface eth0 inet static
netmask 255.255.255.0
gateway 192.168.0.1
 
iface eth1 inet static
address 192.168.1.13
netmask 255.255.255.0
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M


Замена параметра интерфейса.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса, заменяемый параметр и значение передаются параметрами):

  1. #!/bin/sh
  2. [ -z "$1" -o -z "$2" -o -z "$3" ] && exit 1
  3. sed "/iface $1/!b;:x;n;s/$2.*/$2 $3/;t;/iface/b;bx" /etc/network/interfaces

Более подробно на примере sed скрипта:

  1. #!/bin/sed -f
  2. /iface eth0/!b #пока не найду нужный интерфейс прерываю обработку
  3. :x #метка
  4. n #беру на анализ следующую строку
  5. s/netmask.*/netmask 255.255.255.0/ #ищу в строке нужный параметр и заменяю его
  6. t #в случае успешного выполнения предыдушей операции прерываю обработку
  7. /iface/b #если дошел до следующего интерфейса, значит такого параметра нет - прерываю обработку
  8. bx #перехожу на метку "x" (пока не найду нужный параметр)

В результате работы sh скрипта:

$ ./sub_param_iface eth1 address 192.168.3.1
auto lo eth0 eth1
 
iface lo inet loopback
 
iface eth0 inet static
address 192.168.0.13
netmask 255.255.255.0
gateway 192.168.0.1
 
iface eth1 inet static
address 192.168.3.1
netmask 255.255.255.0
 
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M


Добавление параметра интерфейса.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса, добавляемый параметр и значение передаются параметрами):

  1. #!/bin/sh
  2. [ -z "$1" -o -z "$2" -o -z "$3" ] && exit 1
  3. sed "/iface $1/s/$/\n\t$2 $3/" /etc/network/interfaces

Здесь: если строка содержит имя интерфейса, то в конец строки добавляю символ новой строки "\n" и добавляемый параметр со значением


В результате работы sh скрипта:

$ ./add_param_iface eth1 network 192.168.3.0
auto lo eth0 eth1
 
iface lo inet loopback
 
iface eth0 inet static
address 192.168.0.13
netmask 255.255.255.0
gateway 192.168.0.1
 
iface eth1 inet static
address 192.168.3.1
netmask 255.255.255.0
network 192.168.3.0
 
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M


Добавление параметра интерфейса (продвинутый вариант).

Анализирую конфиг на предмет существования этого параметра и если он есть, то заменяю его значение, иначе создаю параметр со значением.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса, добавляемый параметр и значение передаются параметрами):

  1. #!/bin/sh
  2. [ -z "$1" -o -z "$2" -o -z "$3" ] && exit 1
  3. sed "/iface $1/!b;:x;n;s/$2.*/$2 $3/;t;/^[[:space:]]*$/{N;s/\n//;};/iface/s/^/\t$2 $3\n\n/;t;bx" /etc/network/interfaces

Более подробно на примере sed скрипта:

  1. #!/bin/sed -f
  2. /iface eth1/!b #пока не найду нужный интерфейс прерываю обработку
  3. :x #метка
  4. n #беру на анализ следующую строку
  5. s/address.*/address 123.123.123.123/ #если нашел параметр, то заменяю его значение
  6. t #в случае успешной предыдущей операции прервыю обработку
  7. /^[[:space:]]*$/{ #если пустая строка
  8. N #прилепляю конец следующей к этой
  9. s/\n// #удаляю \n
  10. }
  11. /iface/s/^/\taddress 123.123.123.123\n\n/ #если дошел до следующего интерфейса,
  12. #значит такого параметра нет - добавляю параметр и значение
  13.  
  14. t #в случае успешной предыдущей операции прервыю обработку
  15. bx #перехожу на метку "x" (пока не найду нужный параметр)

Еще вариант. Мне он нравится больше:

  1. #!/bin/sed -nf
  2. /iface eth1/!by #пока не найду нужный интерфейс перехожу на метку "y"
  3. :x #метка
  4. :p #вывожу текущую строку на печать
  5. n #беру на анализ следующую строку
  6. s/address.*/address 123.123.123.123/ #если нашел параметр, то заменяю его значение
  7. ty #в случае успешной предыдущей операции перехожу на метку "y"
  8. /^[[:space:]]*$/n #если пустая строка, то пропускаю ее вывод
  9. /iface/s/^/\taddress 123.123.123.123\n\n/ #если дошел до следующего интерфейса,
  10. #значит такого параметра нет - добавляю параметр и значение
  11.  
  12. ty #в случае успешной предыдущей операции перехожу на метку "y"
  13. bx #перехожу на метку "x" (пока не найду нужный параметр)
  14. :y #метка
  15. :p #вывожу текущую строку на печать

В результате работы sh скрипта:

$ ./add_param_iface eth1 network 192.168.3.0
auto lo eth0 eth1
 
iface lo inet loopback
 
iface eth0 inet static
address 192.168.0.13
netmask 255.255.255.0
gateway 192.168.0.1
 
iface eth1 inet static
address 192.168.3.1
netmask 255.255.255.0
network 192.168.3.0
 
iface ath0 inet static
address 192.168.2.13
netmask 255.255.255.0
wireless-essid  home
wireless-nick Notebook
wireless-channel 1
wireless-ap 00:14:86:AC:5A:FA
wireless-rate 54M


Получить значение параметра интерфейса.

sed скрипт в одну строку в теле sh скрипта (имя интерфейса и запрашиваемый параметр передаются параметрами):

  1. #!/bin/sh
  2. [ -z "$1" -o -z "$2" ] && exit 1
  3. sed "/iface $1/!b;:x;n;/$2/p;/iface/b;bx" /etc/network/interfaces

Более подробно на примере sed скрипта:

  1. #!/bin/sed -nf
  2. /iface eth1/!b #пока не найду нужный интерфейс прерываю обработку
  3. :x #метка
  4. n #беру на анализ следующую строку
  5. /address/p #если нашел параметр, то печатаю его
  6. #/address/s/^[[:space:]]*address \(.*\)/\1/p #другой вариант вместо предыдущей строчки - печатает только параметр (вариант 2)
  7. #/address/s/^[[:space:]]*address //p #или еще быстрее (вариант 3)
  8.  
  9. /iface/b #если дошел до следующего интерфейса, то прерываю обработку
  10. bx #перехожу на метку "x" (пока не найду нужный параметр)

В результате работы sh скрипта:

$ ./get_param_iface eth1 address
address 192.168.3.1

В результате работы sh скрипта (в вариантах 1 и 2):

$ ./get_param_iface eth1 address
192.168.3.1


Получить список всех интерфейсов определенного типа.

sed скрипт в одну строку в теле sh скрипта (тип передаются параметром):

  1. #!/bin/sh
  2. [ -z "$1" ] && exit 1
  3. sed -n "/iface .* $1/s/iface \([a-z0-9]*\) .*/\1/p" /etc/network/interfaces

Здесь: если строка содержит небходимый тип интерфейса, то вырезаю имя интерфейса и вывожу его на печать.


В результате работы sh скрипта:

$ ./get_iface_by_type static
eth0
eth1
ath0
Теги: