sed: соединение линий в зависимости от второго - PullRequest
16 голосов
/ 03 апреля 2012

У меня есть файл, который иногда имеет разделенные строки.Разделение сигнализируется тем фактом, что строка начинается с '+' (возможно, с предшествующими пробелами).

line 1
line 2
  + continue 2
line 3
...

Я хотел бы присоединиться к разделенной строке назад:

line 1
line 2 continue 2
line 3
...

используя сед.Мне не понятно, как присоединиться к строке с предшествующей единицей.

Есть какие-нибудь предложения?

Ответы [ 6 ]

20 голосов
/ 04 апреля 2012

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

sed 'N;s/\n\s*+//;P;D' file

На самом деле это четыре команды:

  • N
    Добавить строку из входного файла впробел
  • s/\n\s*+//
    Удалить новую строку, следующий пробел и плюс
  • P
    печать строки от пробела до первой новой строки
  • D
    удалить строку из пространства шаблона до первой новой строки, например, только что напечатанную деталь

Соответствующие части справочной страницы:

3 голосов
/ 03 апреля 2012

Выполнение этого в sed - это, безусловно, хорошее упражнение, но в perl это довольно тривиально:

perl -0777 -pe 's/\n\s*\+//g' input
3 голосов
/ 03 апреля 2012

Я не неравнодушен к sed, поэтому это был хороший вызов для меня.

sed -n '1{h;n};/^ *+ */{s// /;H;n};{x;s/\n//g;p};${x;p}'

В awk это примерно:

awk '
    NR == 1 {hold = $0; next}
    /^ *\+/ {$1 = ""; hold=hold $0; next}
    {print hold; hold = $0}
    END {if (hold) print hold}
'

Если последняя строка - "+ ", версия sed будет печатать завершающую пустую строку.Не могу понять, как это подавить.

2 голосов
/ 04 января 2019

Различное использование пространства удержания с помощью GNU (classic?) Sed ... для основной загрузки всего файла в пространство удержания перед объединением строк.

sed -n '1x;1!H;${g;s/\n\s*+//g;p}'

  • 1x в первой строке, поменять строку в пустом удерживающем пространстве
  • 1!H в не первых строках, добавитьк пробелу
  • $ в последней строке:
    • g получить пробел (весь файл)
    • s/\n\s*+//g заменить символы новой строки, предшествующие +
    • p распечатать все

Ввод:

line 1
line 2
  + continue 2
  + continue 2 even more
line 3
+ continued

становится

line 1
line 2 continue 2 continue 2 even more
line 3 continued

Это (или ответ Потонга) может быть более интересным, чем реализация sed -z, если для других манипуляций с данными требовались другие команды, их можно просто вставить до 1!H, тогда как sed -z немедленно загружает весь файл в пространство шаблона,Это означает, что вы не манипулируете отдельными строками в любой точке.То же самое для perl -0777.

Другими словами, если вы хотите также удалить строки комментариев, начинающиеся с *, добавьте /^\s*\*/d, чтобы удалить строку

sed -n '1x;/^\s*\*/d;1!H;${g;s/\n\s*+//g;p}'

против:

sed -z 's/\n\s*+//g;s/\n\s*\*[^\n]*\n/\n/g'

Накопление первого в линии удержания пространстваза линией вы удерживаете вас в классической области обработки строк sed, в то время как последний sed -z сбрасывает вас в то, что может быть некоторыми болезненными регулярными выражениями подстрок.* обратно в сед.Так что +1 за это.

Сноска для поисковых запросов в Интернете: это синтаксис списка SPICE.

2 голосов
/ 18 июня 2016

Вы можете использовать Vim в режиме Ex:

ex -sc g/+/-j -cx file
  1. g глобальный поиск

  2. - выберите предыдущую строку

  3. j присоединиться к следующей строке

  4. x сохранить и закрыть

1 голос
/ 07 августа 2018

Решение для версий sed, которые могут читать данные, разделенные NUL, как здесь GNU Sed's -z:

sed -z 's/\n\s*+//g'

По сравнению с решением Potong, у него есть преимущество, заключающееся в возможности объединения нескольких строк, начинающихся с +. Например:

line 1
line 2
  + continue 2
  + continue 2 even more
line 3

становится

line 1
line 2 continue 2 continue 2 even more
line 3
...