Sed: соединительные линии в зависимости от второго
У меня есть файл, который иногда имеет разделенные строки. Раскол сигнализируется тем фактом, что линия начинается с "+" (возможно, предшествует пробелам).
line 1
line 2
+ continue 2
line 3
...
Я хочу присоединиться к разделенной строке:
line 1
line 2 continue 2
line 3
...
используя sed. Я не понимаю, как присоединиться к линии с предыдущей.
Любое предложение?
Ответы
Ответ 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
Ответ 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