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

В данное статье показано, как можно выполнять типичные действия над файлом конфигурации средствами 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. #удаляю интерфейс из авто-поднимаемых (ищу строку начинающуюся со слова auto, в ней ищу имя интерфейса (с пробелом или без) и вырезаю его):
  3. /auto/s/eth0 \?//
  4. #### далее удаление интерфейса и его параметров ####
  5. #если строка содержит имя интерфейса, выполняю группу действий:
  6. /iface eth1/{
  7. #метка:
  8. :x
  9. #беру на анализ следующую строку (тем самым пропуская вывод этой):
  10. n
  11. #если начался следующий интерфейс, значит достигнут конец этого интерфейса - перехожу на метку "y":
  12. /iface/by
  13. #перехожу на метку "x" (для удаления остальных параметров этого интерфейса):
  14. bx
  15. }
  16. #метка:
  17. :y
  18. #вывожу текущую строку на печать:
  19. 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. #прерываю анализ строки, пока не найду строку содержащей имя интерфейса
  3. /^iface eth0/!b
  4. #удаляю iface чтобы не мешался:
  5. s/iface //g
  6. #метка:
  7. :x
  8. #если еще не дошел до следующего интерфейса, то:
  9. /iface/!{
  10. #прилепляю следующую строку к концу этой:
  11. N
  12. #перехожу на метку "x":
  13. bx
  14. }
  15. #удаляю все остатки про этот интерфейс:
  16. 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. #пока не найду нужный интерфейс прерываю обработку:
  3. /iface eth0/!b
  4. #метка:
  5. :x
  6. #беру на анализ следующую строку:
  7. n
  8. #ищу параметр и в случае успеха удаляю строку:
  9. /address/d
  10. #если дошел до следующего интерфейса, значит такого параметра нет - прерываю обработку:
  11. /iface/b
  12. #перехожу на метку "x" (пока не найду нужный параметр):
  13. bx

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

  1. #!/bin/sed -nf
  2. #если строка содержит имя интерфейса, выполняю группу действий:
  3. /iface eth0/{
  4. #метка:
  5. :x
  6. #вывожу текущую строку на печать:
  7. p
  8. #беру на анализ следующую строку:
  9. n
  10. #если это строка с параметром, то прерываю анализ строки - тем самым не выводя на печать искомый параметр
  11. /address/b
  12. #если начался следующий интерфейс, значит такого параметра нет - перехожу на метку "y":
  13. /iface/by
  14. #перехожу на метку "x" (для удаления остальных параметров этого интерфейса):
  15. bx
  16. }
  17. #метка:
  18. :y
  19. #вывожу текущую строку на печать:
  20. 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. #пока не найду нужный интерфейс прерываю обработку:
  3. /iface eth0/!b
  4. #метка:
  5. :x
  6. #беру на анализ следующую строку:
  7. n
  8. #ищу в строке нужный параметр и заменяю его
  9. s/netmask.*/netmask 255.255.255.0/
  10. в случае успешного выполнения предыдушей операции прерываю обработку:
  11. t
  12. #если дошел до следующего интерфейса, значит такого параметра нет - прерываю обработку:
  13. /iface/b
  14. #перехожу на метку "x" (пока не найду нужный параметр):
  15. bx

В результате работы 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. #пока не найду нужный интерфейс прерываю обработку:
  3. /iface eth1/!b
  4. #метка:
  5. :x
  6. #беру на анализ следующую строку:
  7. n
  8. #если нашел параметр, то заменяю его значение:
  9. s/address.*/address 123.123.123.123/
  10. #в случае успешной предыдущей операции прервыю обработку:
  11. t
  12. #если пустая строка
  13. /^[[:space:]]*$/{
  14. #прилепляю конец следующей к этой
  15. N
  16. #удаляю \n
  17. s/\n//
  18. }
  19. #если дошел до следующего интерфейса, значит такого параметра нет - добавляю параметр и значение:
  20. /iface/s/^/\taddress 123.123.123.123\n\n/
  21. #в случае успешной предыдущей операции прервыю обработку:
  22. t
  23. #перехожу на метку "x" (пока не найду нужный параметр):
  24. bx

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

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

В результате работы 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