Как заменить символ новой строки (\ n) с помощью sed? - PullRequest
1233 голосов
/ 09 августа 2009

Как заменить символ новой строки (\n) командой sed?

Я безуспешно пытался:

sed 's#\n# #g' file
sed 's#^$# #g' file

Как мне это исправить?

Ответы [ 41 ]

1569 голосов
/ 09 августа 2009

Использовать tr вместо?

tr '\n' ' ' < input_filename

или полностью удалите символы новой строки:

tr -d '\n' < input.txt > output.txt

или, если у вас версия GNU (с ее длинными опциями)

tr --delete '\n' < input.txt > output.txt
1392 голосов
/ 10 августа 2009

Используйте это решение с GNU sed:

sed ':a;N;$!ba;s/\n/ /g' file

Это прочитает весь файл в цикле, а затем заменит символы новой строки пробелом.

Пояснение:

  1. Создать ярлык через :a.
  2. Добавить текущую и следующую строку к пробелу с помощью N.
  3. Если мы находимся перед последней строкой, переходите к созданной метке $!ba ($! означает, что не следует делать это в последней строке, так как должен быть один последний перевод строки).
  4. Наконец, подстановка заменяет каждую новую строку пробелом в пространстве образца (который является целым файлом).

Вот кроссплатформенный совместимый синтаксис, который работает с BSD и OS X sed (согласно @ Benjie comment ):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

Как видите, использование sed для решения этой простой проблемы проблематично. Для более простого и адекватного решения см. этот ответ .

448 голосов
/ 08 октября 2011

Быстрый ответ:

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a создать ярлык 'a'
  2. N добавить следующую строку в пространство образца
  3. $! если не последняя строка , ba ветвь (перейти к) метка 'a'
  4. с заменить , / \ n / регулярное выражение для новой строки , / / через пробел , / г глобальное совпадение (столько раз, сколько возможно)

sed будет перебирать шаги с 1 по 3 до тех пор, пока не достигнет последней строки, в результате чего все строки поместятся в пространство шаблона, где sed заменит все \ n символов


Альтернативы

Все альтернативы, в отличие от sed , для начала процесса не нужно достигать последней строки

с удар , медленно

while read line; do printf "%s" "$line "; done < file

с perl , sed -подобная скорость

perl -p -e 's/\n/ /' file

с tr , быстрее, чем sed , можно заменить только одним символом

tr '\n' ' ' < file

с вставкой , tr -подобной скоростью, можно заменить только одним символом

paste -s -d ' ' file

с awk , tr -подобная скорость

awk 1 ORS=' ' file

Другая альтернатива, такая как "echo $ ( работает медленно, работает только с небольшими файлами и требует обработки всего файла, чтобы начать процесс.


Длинный ответ из sed FAQ 5.10 :

5,10. Почему я не могу сопоставить или удалить символ новой строки с помощью \ n escape
последовательность? Почему я не могу сопоставить 2 или более строк, используя \ n?

\ n никогда не будет соответствовать новой строке в конце строки, потому что
символ новой строки всегда удаляется до помещения строки в
образец пространства. Чтобы получить 2 или более строк в пространство шаблона, используйте
команда 'N' или что-то подобное (например, 'H; ...; g;').

Sed работает следующим образом: sed читает по одной строке за раз, отключает
завершающий перевод строки, помещает то, что осталось в пространство шаблона, где
Сценарий Sed может адресовать или изменять его, и когда образец пространства
печатается, добавляет новую строку в стандартный вывод (или в файл). Если
пространство образца полностью или частично удаляется с помощью 'd' или 'D',
В таких случаях добавляется символ новой строки , а не . Таким образом, сценарии типа

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

НИКОГДА не будет работать, потому что завершающий символ новой строки удаляется до
линия помещается в пространство шаблона. Для выполнения вышеуказанных задач
используйте вместо этого один из этих сценариев:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Поскольку версии sed, кроме GNU sed, имеют ограничения на размер
буфер шаблонов, утилита Unix 'tr' должна быть здесь предпочтительней.
Если последняя строка файла содержит символ новой строки, GNU sed добавит
перевод строки в вывод, но удаление всех остальных, тогда как tr будет
удалить все новые строки.

Чтобы сопоставить блок из двух или более строк, есть 3 основных варианта:
(1) используйте команду 'N', чтобы добавить следующую строку в пространство шаблона;
(2) использовать команду «H» как минимум дважды, чтобы добавить текущую строку
в пространство удержания, а затем получить линии из пространства удержания
с х, г или G; или (3) использовать диапазоны адресов (см. раздел 3.3 выше)
чтобы сопоставить строки между двумя указанными адресами.

Выбор (1) и (2) поместит \ n в пространство шаблона, где оно
могут быть адресованы по желанию ('s / ABC \ nXYZ / алфавит / g'). Один пример
использование 'N' для удаления блока строк приведено в разделе 4.13
(«Как удалить блок из определенных последовательных строк?»). Это
пример можно изменить, изменив команду delete на что-то
иначе, например, «p» (печать), «i» (вставка), «c» (изменение), «a» (добавление),
или 's' (заменить).

Выбор (3) не помещает \ n в пространство шаблона, но он делает
сопоставлять блок последовательных строк, поэтому может быть, что вы не
даже нужно \ n, чтобы найти то, что вы ищете. С GNU sed
версия 3.02.80 теперь поддерживает этот синтаксис:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

в дополнение к традиционному диапазону '/ from here /, / to there / {...}'
адресов, возможно, можно полностью избежать использования \ n.

207 голосов
/ 13 февраля 2013

Более короткая альтернатива awk:

awk 1 ORS=' '

Объяснение

Программа awk состоит из правил, которые состоят из условных кодовых блоков, т. Е .:

.
condition { code-block }

Если кодовый блок опущен, используется значение по умолчанию: { print $0 }. Таким образом, 1 интерпретируется как истинное условие, а print $0 выполняется для каждой строки.

Когда awk читает входные данные, он разбивает его на записи на основе значения RS (Разделитель записей), которое по умолчанию является новой строкой, поэтому awk будет по умолчанию анализировать ввод по строке. Разделение также включает удаление RS из входной записи.

Теперь при печати записи к ней добавляется ORS (Разделитель выходных записей), по умолчанию снова вводится новая строка. Таким образом, изменяя ORS на пробел, все новые строки заменяются пробелами.

119 голосов
/ 05 мая 2015

gnu sed имеет опцию -z для записей, разделенных нулями (строк). Вы можете просто позвонить:

sed -z 's/\n/ /g'
83 голосов
/ 09 августа 2009

Версия Perl работает так, как вы ожидали.

perl -i -p -e 's/\n//' file

Как отмечено в комментариях, стоит отметить, что это редактирует на месте. -i.bak даст вам резервную копию исходного файла перед заменой на случай, если ваше регулярное выражение окажется не таким умным, как вы думали.

43 голосов
/ 11 августа 2010

Кому нужно sed? Вот способ bash:

cat test.txt |  while read line; do echo -n "$line "; done
24 голосов
/ 30 марта 2012

Чтобы заменить все символы новой строки пробелами, используя awk, без чтения всего файла в память:

awk '{printf "%s ", $0}' inputfile

Если вы хотите заключительный перевод строки:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

Вы можете использовать символ, отличный от пробела:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile
20 голосов
/ 13 апреля 2014
tr '\n' ' ' 

- это команда.

Простой и удобный в использовании.

20 голосов
/ 01 мая 2011

Три вещи.

  1. tr (или cat и т. Д.) Абсолютно не нужны. (GNU) sed и (GNU) awk, если объединены, могут выполнять 99,9% любой необходимой обработки текста.

  2. stream! = На основе строки. ed - это линейный редактор. sed нет. См. sed lecture для получения дополнительной информации о разнице. Большинство людей путают sed со строками, потому что по умолчанию он не слишком жадный в сопоставлении с шаблоном для совпадений SIMPLE - например, при поиске и замене шаблона по одному или двум символам, он по умолчанию заменяет только на первое найденное совпадение (если не указано иное глобальной командой). Не было бы даже глобальной команды, если бы она основывалась на строках, а не на STREAM, потому что она будет оценивать только строки за раз. Попробуйте запустить ed; Вы заметите разницу. ed очень полезен, если вы хотите перебирать определенные строки (например, в цикле for), но в большинстве случаев вам просто нужно sed.

  3. Как говорится,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    прекрасно работает в GNU sed версии 4.2.1. Приведенная выше команда заменит все новые строки пробелами. Это некрасиво и немного громоздко набирать, но работает просто отлично. {} можно не указывать, поскольку они включены только по соображениям здравого смысла.

...