Sed многострочный поиск и замена: удалить и добавить вторую подходящую строку к первой - PullRequest
1 голос
/ 09 апреля 2020

У меня есть несколько строк в файле, которые были изменены какой-то программой java, и строки, содержащие '\n', автоматически разбились на 2 строки. Я хочу использовать sed, чтобы изменить их обратно.

Требование: Искать только совпадающие строки. Удалите вторую строку и добавьте к предыдущей.

Eg:
line 1: LINES TERMINATED BY '
line 2: '  STORED AS INPUTFORMAT

Output Expected:
line 1: LINES TERMINATED BY ''  STORED AS INPUTFORMAT

Итак, сначала найдите эту последовательность слов в последующих строках, а затем удалите вторую и добавьте к первой.

Решение, которое я пробовал:

sed -e "/LINES TERMINATED BY '/N;s/'  STORED AS INPUTFORMAT/LINES TERMINATED BY ''  STORED AS INPUTFORMAT/ external_revenue.sql > myfile_new.txt

Изменяет вторую строку, но не удаляет и не добавляет ее к первой.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Это может сработать для вас (GNU sed):

sed ":a;N;s/'\n'/''/;ta;P;D" file

Сформировать работающее окно из двух строк.

Если конец первой строки равен ', а начало второй строки - ', удалите новую строку между ними и повторяйте, пока больше не будет совпадений.

Распечатайте / удалите первую строку и повторите.

0 голосов
/ 09 апреля 2020

Появляется следующая программа sed. Я подчеркнул буквальные строки для строки 1 и строки 2 :

/LINES TERMINATED BY '$/{N;s/\n\('  STORED AS INPUTFORMAT\)/\1/;}
 ^^^^^^^^^^^^^^^^^^^^^           ^^^^^^^^^^^^^^^^^^^^^^^^

Разбивка

Соответствие строка 1 :

/LINES TERMINATED BY '$/{N;s/\n\('  STORED AS INPUTFORMAT\)/\1/;}
^^^^^^^^^^^^^^^^^^^^^^^^

Выполнить все команды в блоке между { и } при совпадении:

/LINES TERMINATED BY '$/{N;s/\n\('  STORED AS INPUTFORMAT\)/\1/;}
                        ^                                       ^

Первая команда: добавить следующую строку (т.е. строка 2 ) к текущему образцу (т. Е. Добавить к концу строка 1 ). После добавления пространство шаблона будет содержать разделитель новой строки между строка 1 и строка 2 :

/LINES TERMINATED BY '$/{N;s/\n\('  STORED AS INPUTFORMAT\)/\1/;}
                         ^

Вторая команда: заменить первое (и только) вхождение из «новой строки, за которой следует строка 2 » с просто « строка 2 » (т.е. удалить новую строку):

/LINES TERMINATED BY '$/{N;s/\n\('  STORED AS INPUTFORMAT\)/\1/;}
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Если s/// не совпадает новая строка из строка 1 сохраняется, а пространство шаблона ( строка 1 '\ n' строка 2 ) выводится как-по существу, сохраняя обе строки без изменений.

Цитирование bash

'/LINES TERMINATED BY '"'"'$/{N;s/\n\('"'"'  STORED AS INPUTFORMAT\)/\1/;}'
 ^^^^^^^^^^^^^^^^^^^^^ ~~~ ^^^^^^^^^^^ ~~~ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Символы, выделенные ^, сохраняются в одинарных кавычках. Шаблоны, выделенные ~, вводят буквальную одинарную кавычку ' в строке.



Альтернативное решение

Если ваш sed поддерживает -z опцию, вы должны иметь возможность сделать это следующим образом:

sed -z -e 's/LINES TERMINATED BY '"'"'\n'"'"'  STORED AS INPUTFORMAT/LINES TERMINATED BY '"''"'  STORED AS INPUTFORMAT/g' external_revenue.sql > myfile_new.txt

Использование -z (данные, разделенные NUL) позволяет сопоставлять новые строки (используя \n') непосредственно в регулярном выражении поиска.


Образец external_revenue.sql:

LINES OK
LINES TERMINATED BY '
'  STORED AS INPUTFORMAT
LINES OK
LINES OK
LINES TERMINATED BY '
'  STORED AS INPUTFORMAT
LINES OK

Сеанс терминала:

$ sed -z -e 's/LINES TERMINATED BY '"'"'\n'"'"'  STORED AS INPUTFORMAT/LINES TERMINATED BY '"''"'  STORED AS INPUTFORMAT/g' external_revenue.sql 
LINES OK
LINES TERMINATED BY ''  STORED AS INPUTFORMAT
LINES OK
LINES OK
LINES TERMINATED BY ''  STORED AS INPUTFORMAT
LINES OK
...