LINUX.ORG.RU
ФорумAdmin

Хитрый sed?

 , lease,


0

2

Как с помощью однострочника изменить в файле /var/lib/dhcp3/dhcpd.leases последний lease для ip?

Пример файла:

...

lease 192.168.10.59 {

starts 6 2012/06/09 02:13:31;

ends 6 2012/06/09 02:43:31;

cltt 6 2012/06/09 02:13:31;

binding state active;

next binding state free;

hardware ethernet 00:00:06:a7:b6:fd;

uid «\001\000\300&\247\266\375»;

client-hostname «001-WS»;

}

lease 192.168.10.13 {

starts 6 2012/06/09 03:12:20;

ends 6 2012/06/09 03:42:20;

cltt 6 2012/06/09 03:12:20;

binding state active;

next binding state free;

hardware ethernet 00:11:11:11:8c:97;

uid «\001\000\021\021G\214\227»;

client-hostname «002-ws»;

}

lease 192.168.10.59 {

starts 6 2012/06/09 03:13:31;

ends 6 2012/06/09 03:43:31;

cltt 6 2012/06/09 03:13:31;

binding state active;

next binding state free;

hardware ethernet 00:00:06:a7:b6:fd;

uid «\001\000\300&\247\266\375»;

client-hostname «001-WS»;

}

...

Нужно заменить строчку строчку содержащую «ends» у последнего совпадения ip 192.168.10.59

Пока получилось показать и изменить последний lease для ip:

cat /var/lib/dhcp3/dhcpd.leases | grep «lease 192.168.10.75» -A9 | tail -n10 | sed «/ends/s/.*/ ends 6 `date '+%Y/%m/%d %T' | sed 's/\//\\\\\//g'`/»

заменить сам файл этим выводом не могу т.к. выводится только один ip

★★

Последнее исправление: lioncub (всего исправлений: 4)

ИМХО, это проще решать не одним sed, а двумя. Сначала получить номер нужно строки, потом сделать замену в этой строке.

Вот так получаются все номера строк с ends для заданного ip-адреса:

cat -n /var/lib/dhcp3/dhcpd.leases | sed -n -e '/lease 192.168.10.59/,/}/s/ends .*//p'

Вот так получается номер последней строки, хотя можно предыдущую команду пропустить через tail или загрузить в массив bash'а:

cat -n /var/lib/dhcp3/dhcpd.leases | sed -n -e '/lease 192.168.10.59/,/}/{s|ends .*||;tb;ba;:b;x;:a;}' -e '$!d' -e '$x;p'

Ну, а по номеру строки (в bash переменной NUM) уже можно делать так:

sed «${NUM}s/.*/ends 6 `date '+%Y/%m/%d %T'`»

Только я не понял, зачем вам «sed 's/\//\\\\\//g'», все нужные слеши можно засунуть в команду date.

mky ★★★★★
()
Ответ на: комментарий от drBatty

Ваш sed делает не совсем то, что хотел ТС, он меняет ends последней lease в файле, а не последней для заданного ip-адреса. И даёт пустую строку в начале вывода. Но скрипт можно улучшить, я правда не понял, зачем конструкция:

«x;p;x;h;b»

почему не просто «x;p;b» ?

Другое дело, что судя по тому, что писал ТС, ему длинные команды в sed не понятны и врятли он будет с ними разбиратся. А подход с определеним номера нужной строки проще и он сможет в дальнейшем писать свои костыли не задавая каждый раз вопрос на ЛОРе по поводу сложной sed-команды.

mky ★★★★★
()
Ответ на: комментарий от mky

Ваш sed делает не совсем то, что хотел ТС, он меняет ends последней lease в файле, а не последней для заданного ip-адреса.

ну поменяйте lease в скрипте на lease 1.2.3.4, не вижу проблемы. Или там есть такие хитрые lease без ends?

И даёт пустую строку в начале вывода.

I like it

я правда не понял, зачем конструкция: «x;p;x;h;b» почему не просто «x;p;b» ?

вот я буду часами думать об этом... В следующий раз напишу x;p;b...

Другое дело, что судя по тому, что писал ТС, ему длинные команды в sed не понятны и врятли он будет с ними разбиратся. А подход с определеним номера нужной строки проще и он сможет в дальнейшем писать свои костыли не задавая каждый раз вопрос на ЛОРе по поводу сложной sed-команды.

время покажет...

drBatty ★★
()
Ответ на: комментарий от mky

да, действительно «sed 's/\//\\\\\//g'» тут не нужен...

почему одним... потомучто строка может измениться...

lioncub ★★
() автор топика
Ответ на: комментарий от lioncub

Делаете копию файла, там всё меняете и записываете файл обратно. Всё равно, sed (даже с -i) сначала создаст изменённый файл, а потом запишет его обратно и если какой-то другой процесс одновременно с sed будет изменять /var/lib/dhcp3/dhcpd.leases результат будет неопределён.

mky ★★★★★
()
Ответ на: комментарий от mky

ладно... пока буду тупо его убивать при изменениях.... пока руки не дошли... а так и на perl'e можно накатать быстренько (не однострочник)

спасибо!

lioncub ★★
() автор топика
Ответ на: комментарий от mky

Всё равно, sed (даже с -i) сначала создаст изменённый файл, а потом запишет его обратно

нет. Sed создаст временный файл, а потом его _переименует_.

и если какой-то другой процесс одновременно с sed будет изменять /var/lib/dhcp3/dhcpd.leases результат будет неопределён.

Вполне определён. Операция переименования атомарна в рамках ФС, и потому никакой неоднозначности быть не может - либо sed переименует свою временную копию, а потом процесс, либо наоборот, в зависимости от того, что произойдёт раньше. Естественно, это в случае, если другой процесс работает так же как sed, что в большинстве случаев на практике наблюдается. (да, мы в Linux'е, и можем написать хитрый процесс, который плевал на правила. В этом случае _можно_ получить неопределённый результат. Не нужно мне это доказывать, я и сам в курсе. С дуру можно и член поломать.)

drBatty ★★
()
Ответ на: комментарий от lioncub

ладно... пока буду тупо его убивать при изменениях.... пока руки не дошли... а так и на perl'e можно накатать быстренько (не однострочник)

на самом деле, у меня тут тоже не однострочник. Это только на ЛОРе я так выделываюсь, IRL сложные одностроки не нужны. Sed это тоже ЯП, и он попроще перловки будет...

drBatty ★★
()
Ответ на: комментарий от drBatty

спасибо, вроде получается...

lioncub ★★
() автор топика
Ответ на: комментарий от drBatty

Давно это «либо-либо» стало означать определённый результат? Кот Шрёдингера «либо становится мёртвым, либо остаётся живым» — это тоже определёный результат?

Причём не надо тут играть в КО и приплетать правила работы процессов с файлами. В данном контексте определённость результата означает, будет ли решена задача ТС по требуемому ему изменению параметров лизы после выполнения скрипта или нет.

Судя под этому:

пока буду тупо его убивать при изменениях

ТС правильно понял, что я хотел сказать.

mky ★★★★★
()
Ответ на: комментарий от drBatty

Кстати, получается, хоть это и не принято, что если делать не rename(), а open(O_TRUNC), write(), то сохраняются атрибуты файла (права доступа, SeLinux и т.д.).

Интерестно, есть аналог «chmod –reference», но только переносящий все атрибуты файла?

mky ★★★★★
()
Ответ на: комментарий от mky

Давно это «либо-либо» стало означать определённый результат?

всегда. содержимое файла будет таким, которым его оставил последний процесс. Вот если-бы, как вы пишете,

а потом запишет его обратно

то тут да, возникает неопределённость - файл может и изменится _непредсказуемо_, если его _пишут_ два процесса. Фишка в том, что процесс _записи_ не является атомарным, в отличие от переименования. (правда можно избежать неоднозначности, если записывать _всегда_ в конец файла, и небольшими порциями. Так, как пишутся логи)

В данном контексте определённость результата означает, будет ли решена задача ТС по требуемому ему изменению параметров лизы после выполнения скрипта или нет.

ну сиё мне неведомо, потому я рассматриваю довольно общий случай, хотя и предполагаю, что другой процесс работает также, как и sed.

Кстати, получается, хоть это и не принято, что если делать не rename(), а open(O_TRUNC), write(), то сохраняются атрибуты файла (права доступа, SeLinux и т.д.).

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

drBatty ★★
()
Ответ на: комментарий от drBatty

Под «запишет обратно» я не подразумевал open()+write(). Я знаю, что там используется rename() временного файла. Просто, когда я первый раз читал описание «sed -i», не помню где, там именно было использовано словосочетание «write back», как, допустим, здесь http://unstableme.blogspot.com/2010/01/sed-save-changes-to-same-file.html :

Today I am going to show how we can use sed to do some operation on a file ... and write back the results to the same file.

Видимо так это у меня в голове и засело.

Не знаю как под 2.6 и 3.x ядрами, но под 2.4 write() на файл на локальной ФС был атомарен, независимо от размера (хоть 500 Мбайт), другое дело, что fwrite() разбивается на кучу write() тогда и возникает мешанина. Может сейчас что и поменялось, а тогда получалось, что write() переводило процесс в uninterruptible sleep (D state) и процесс, производящий запись в этот же файл ждал пока закончится write() первого процесса. Правда, не помню, как вёл себя read(), пока выполялся write().

mky ★★★★★
()
Ответ на: комментарий от mky

когда я первый раз читал описание «sed -i», не помню где, там именно было использовано словосочетание «write back», как, допустим, здесь http://unstableme.blogspot.com/2010/01/sed-save-changes-to-same-file.html :

я тоже был несколько удивлён тому, что на самом деле значит «in place»...

Не знаю как под 2.6 и 3.x ядрами, но под 2.4 write() на файл на локальной ФС был атомарен

я точно не помню, но, если мне не изменяет память, в 2.6+ атомарность гарантируется только при записи небольших кусков (512 байт вроде максимум), для бОльших кусков она тоже гарантируется, но вот насколько бОльших - зависит уже от реализации.

drBatty ★★
()
Ответ на: комментарий от drBatty

512 байт это PIPE_BUF (его минимальный размер по POSIX). А вот writev() действительно атомарен под Линуксом, или я как-то не так понимаю man?

mky ★★★★★
()
Ответ на: комментарий от mky

А вот writev() действительно атомарен под Линуксом, или я как-то не так понимаю man?

присоединяюсь к вопросу.

drBatty ★★
()
Ответ на: комментарий от lioncub

судя по тому как работает dhcpd, то он именно в конец файла дописывает лизы...

ну да.

drBatty ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.