Подтвердить что ты не робот

Sed: соединительные линии в зависимости от второго

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

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

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

line 1
line 2 continue 2
line 3
...

используя sed. Я не понимаю, как присоединиться к линии с предыдущей.

Любое предложение?

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

Я не являюсь частичным для 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 напечатает завершающую пустую строку. Не удалось выяснить, как его подавить.

Ответ 3

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

perl -0777 -pe 's/\n\s*\+//g' input

Ответ 4

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

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

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

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

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

Ответ 5

Различное использование пространства удержания с помощью POSIX 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

Это (или ответ potong) может быть более интересным, чем реализация 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 сбрасывает вас в то, что может быть некоторыми болезненными регулярными выражениями подстрок.

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

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

Ответ 6

Решение для версий sed, которые могут читать данные, разделенные NUL, как здесь GNU Sed -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