Regexp в нескольких файлах

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Ответить
legushonok
Сообщения: 19

Regexp в нескольких файлах

Сообщение legushonok »

Добрый день.
Собственно есть куча файлов в которых нужно заменить код:

Код:

if (!session_is_registered("auth")) { exit; }


на

Код:

if(!isset($_SESSION["auth"])) exit;


С регой знаком не очень хорошо и сложно представляю как заменять сложные выражения.
Просьба помочь.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Regexp в нескольких файлах

Сообщение SLEDopit »

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

Код: Выделить всё

for file in *mask ; do
sed -i.bak '/if.*session_is_registered/{N;N;N;s/if (!session_is_registered("auth"))\s*\n\s*{\s*\n\s*exit;\s*\n\s*}/if(!isset($_SESSION["auth"])) exit;/;}' $file ;
done

-i.bak сохранит оригинал, прибавив к его имени .bak.
на всякий случай я бы рекомендовал делать именно так, чтобы, если вдруг что-о пойдёт не так, можно было откатить изменения. если же всё хорошо, то можно будет просто удалить лишние файлы.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
legushonok
Сообщения: 19

Re: Regexp в нескольких файлах

Сообщение legushonok »

Спасибо большое за помощь.
Бэкаплюсь обычно по несколько раз перед ломанием.
Спасибо сказали:
sciko
Сообщения: 1744
Статус: Ъ-участник
ОС: Debian/Ubuntu/etc

Re: Regexp в нескольких файлах

Сообщение sciko »

Вопрос про многострочную замену в sed довольно распространён, но, увы, SLEDopit ответил на него неверно.

sciko

$ cat test.txt if (!session_is_registered("none")) exit; if (!session_is_registered("auth")) { exit; } $ sed -e '/if.*session_is_registered/{N;N;N;s/if (!session_is_registered("auth"))\s*\n\s*{\s*\n\s*exit;\s*\n\s*}/if(!isset($_SESSION["auth"])) exit;/;}' test.txt if (!session_is_registered("none")) exit; if (!session_is_registered("auth")) { exit; } $ WTF?



В чём же причина? А причина одна -- безблагодатность неверный алгоритм.

Как работает вышеописанный скрипт для sed? Сперва ищется строка совпадающая с регэкспом "if.*session_is_registered". Если она найдена, то выполняется блок команд (те, что между фигурными скобками).
Сам блок команд же очень прост: в рабочий буфер sed считывается ещё 3 строки ("N;N;N;"), после чего происходит попытка замены через операцию s///.

Однако проблема в том, что, если регэксп "if.*session_is_registered" совпадает с некой строкой, то ещё 3 строки считываются в любом случае, даже если там не произошло замены. Если же на эти 3 строки попадётся нужный для замены участок, то он будет пропущен.

Так какой же вариант правильный? Увы и ах, он очень сложен. Поэтому я приведу просто работоспособный:

Код: Выделить всё

for file in *mask ; do sed -i.bak ':a;N;s/if (!session_is_registered("auth"))\s*\n\s*{\s*\n\s*exit;\s*\n\s*}/if(!isset($_SESSION["auth"])) exit;/g;ta' $file ; done


Как это работает?
Создаётся метка "a" (команда ":a;"). Далее считывается очередная строка (команда ":N;") и производится попытка замены. Если попытка замены -- неудачная, то происходит переход на метку "a" (команда "ta;").

Почему этот скрипт -- неверный? Потому что, если в файле менять нечего, то в рабочий буфер sed будет считан весь файл, что не есть хорошо.
Спасибо сказали:
liaonau
Сообщения: 390
ОС: gentoo

Re: Regexp в нескольких файлах

Сообщение liaonau »

sciko писал(а):
25.10.2013 01:40
Почему этот скрипт -- неверный? Потому что, если в файле менять нечего, то в рабочий буфер sed будет считан весь файл, что не есть хорошо.

В данном случае из самого текста для замены ясно, что файл это исходник или скрипт — в-общем такой, который, вероятно, редактируется вручную в
текстовом редакторе (явно не несколько гигабайт размером). Редактор же считывает его в буфер полностью и ничего страшного.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

sciko писал(а):
25.10.2013 01:40
Почему этот скрипт -- неверный? Потому что, если в файле менять нечего, то в рабочий буфер sed будет считан весь файл, что не есть хорошо.

вы можете

1. считать 4 строки N;N;N;N

2. поискать нужное

3. если не нашли, считать ещё строку N, и удалить одну старую D, и затем goto 2

таким образом, в буфере sed будет всегда 4 строки.


liaonau писал(а):
25.10.2013 02:39
В данном случае из самого текста для замены ясно, что файл это исходник или скрипт — в-общем такой, который, вероятно, редактируется вручную в
текстовом редакторе

вы первый пост читали? Как вы собрались over9000 файлов СРАЗУ редактировать? Такое разве что в vim'е можно (только я никогда так не делаю, ибо есть sed)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
liaonau
Сообщения: 390
ОС: gentoo

Re: Regexp в нескольких файлах

Сообщение liaonau »

drBatty писал(а):
26.10.2013 18:16
Как вы собрались over9000 файлов СРАЗУ редактировать?

Это не было предложением редактировать вручную. Это было предположением, что нет ничего страшного в том, чтобы прочитать в буфер sed весь файл целиком.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

liaonau писал(а):
27.10.2013 09:41
Это было предположением, что нет ничего страшного в том, чтобы прочитать в буфер sed весь файл целиком.

зачем так делать, если можно сделать намного лучше?
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
sciko
Сообщения: 1744
Статус: Ъ-участник
ОС: Debian/Ubuntu/etc

Re: Regexp в нескольких файлах

Сообщение sciko »

drBatty писал(а):
26.10.2013 18:16
1. считать 4 строки N;N;N;N

Достаточно 3 N;, т.к. одна строка всегда считывается при начале sed-сценария.

drBatty писал(а):
26.10.2013 18:16
3. если не нашли, считать ещё строку N, и удалить одну старую D, и затем goto 2

Идея правильная, но D просто удаляет строку из буфера, а надо её ещё и вывести. Кроме того, D автоматом бросает на начало sed-сценария.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

sciko писал(а):
28.10.2013 01:06
Достаточно 3 N;, т.к. одна строка всегда считывается при начале sed-сценария.

я по опыту знаю, что код проще, если в буфере n+1 строка. Но да, в теории можно и n строк, но тогда код получается более сложный.
sciko писал(а):
28.10.2013 01:06
Идея правильная, но D просто удаляет строку из буфера, а надо её ещё и вывести.

про команду P вы не слышали? А для кого я учебник-то писал?! Вот вам пример: http://emulek.github.io/sed/ch07.html#info_uniq



sciko писал(а):
28.10.2013 01:06
Кроме того, D автоматом бросает на начало sed-сценария.

а мужики-то не знали...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
sciko
Сообщения: 1744
Статус: Ъ-участник
ОС: Debian/Ubuntu/etc

Re: Regexp в нескольких файлах

Сообщение sciko »

drBatty писал(а):
28.10.2013 10:30
Но да, в теории можно и n строк, но тогда код получается более сложный.
С чего бы это?


drBatty писал(а):
28.10.2013 10:30
про команду P вы не слышали?

drBatty писал(а):
28.10.2013 10:30
а мужики-то не знали...
А если знаете, то зачем даёте заведомо неверный алгоритм?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

sciko писал(а):
28.10.2013 22:02
Но да, в теории можно и n строк, но тогда код получается более сложный.

С чего бы это?

попробуйте, и поймёте. Может я и ошибаюсь, не каждый день это надо.

sciko писал(а):
28.10.2013 22:02
А если знаете, то зачем даёте заведомо неверный алгоритм?

а вы по ссылке сходите. Алгоритм верный, там D используется. А для печати -- вот как раз P. Может я виноват ещё и в том, что весь код не написал для вас? Похоже ТСу он и не нужен, он свою задачу решил уже. А ежели кто забредёт сюда потом, то у него будет немного другая задача, и мой готовый код ему не пойдёт. Зачем же я его писать должен?

http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
sciko
Сообщения: 1744
Статус: Ъ-участник
ОС: Debian/Ubuntu/etc

Re: Regexp в нескольких файлах

Сообщение sciko »

drBatty писал(а):
28.10.2013 23:01
Алгоритм верный, там D используется.
Так все говорят.

drBatty писал(а):
26.10.2013 18:16
1. считать 4 строки N;N;N;N

2. поискать нужное

3. если не нашли, считать ещё строку N, и удалить одну старую D, и затем goto 2


Давайте разбирать по шагам:

1) Считали 4 строки. Теперь их в буфере 5 (с 1 по 5).

2) Поискали, не нашли

3) Считываем ещё одну строку (теперь с 1 по 6), выводим первую (P) и удаляем её через D (теперь с 2 по 6)

4) goto 2 А вот и хрен! D перебрасывает нас на 1.

5) Считываем ещё 5 строк (с 2 по 11)

.......

И так будет набираться, пока не будет обнаружено совпадение, как и в более коротком варианте выше.
А если в файле не будет вообще ни одного совпадения, то на выходе получим только первые 1/5 файла, выведенные командой P, остальные останутся в буфере.

drBatty писал(а):
28.10.2013 23:01
Может я виноват ещё и в том, что весь код не написал для вас?

Мне не надо, я знаю правильный вариант.

drBatty писал(а):
28.10.2013 23:01
А ежели кто забредёт сюда потом, то у него будет немного другая задача, и мой готовый код ему не пойдёт.

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

Не хотите исправлять? И не надо! Но хотя бы не отрицайте, что алгоритм указывает только на направление решения, а не является решением.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

sciko писал(а):
29.10.2013 00:26
А вот и хрен! D перебрасывает нас на 1.

ну что вы как дети малые? Такое ощущение, что вы компьютер впервые увидели... Ну понятно, что надо начать с п2

Код: Выделить всё

# 2. если строка №1 идём на :begin
1b begin
# 2.1...

# 3... D перебрасывает нас в начало

# ...
b # конец

:begin
#тут начало.

sciko писал(а):
29.10.2013 00:26
А ваш алгоритм не подойдёт по другой причине: в нём ошибки, его нельзя повторно использовать.

у меня именно что _алгоритм_, а не реализация. Ссылка на учебник в подписи есть. Это если непонятно, как реализовывать. ЕМНИП там этот момент с D подробно обсасывается. Я что, должен в каждой теме одно и то же писать? Зачем? Если у меня в учебнике этот момент недостаточно полно рассмотрен -- так и пишите: вот, у тебя всё плохо. Я исправлю. А переписывать-то зачем?
sciko писал(а):
29.10.2013 00:26
Не хотите исправлять? И не надо! Но хотя бы не отрицайте, что алгоритм указывает только на направление решения, а не является решением.

у нас с вами разное понимание слова "алгоритм". Я это понимаю именно как направление. Особенно учитывая, что подробное описание команд с примерами у меня есть, лежит на github'е. Не вижу проблемы.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
nerve
Сообщения: 280
ОС: OpenBSD

Re: Regexp в нескольких файлах

Сообщение nerve »

парни, так какое универсальное решение для замены по шаблону нескольких строк?

Код: Выделить всё

abc
def    на   ххх
ghi


заменить во всем/всех файлах три строки с шаблоном из букв на строку с ххх
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Контактная информация:

Re: Regexp в нескольких файлах

Сообщение drBatty »

nerve писал(а):
30.10.2013 01:14
парни, так какое универсальное решение для замены по шаблону нескольких строк?

см. http://emulek.github.io/sed/ch04s07.html

вот Пример 4.9, там текст делится на предложения. "Предложения" там == любые посл. символов, которые кончаются [.?!].

и да, ещё один способ: http://emulek.github.io/sed/ch04s09.html
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Ответить