Как заменить новую строку (n) с помощью sed?

Как я могу заменить новую строку (n) С помощью команды sed?

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

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

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

30 ответов


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

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

это прочитает весь файл в цикле, а затем заменит новую строку(строки) пробелом.

объяснение:

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

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

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

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


использовать ?

tr '\n' ' ' < input_filename

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

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

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

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

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

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

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;...;г.)';

Sed работает следующим образом: sed читает одну строку за раз, отрубает
завершая новую строку, помещает то, что осталось в пространство шаблонов, где
сценарий sed может адресовать или измените его, и когда pattern space
печатается, добавляет новую строку в stdout (или в файл). Если
пространство шаблонов полностью или частично удаляется с помощью " 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 " по крайней мере дважды, чтобы добавить текущую строку
в пространство удержания, а затем получить строки из пространства удержания
или (3) использовать диапазоны адресов (см. раздел 3.3, выше)
для сопоставления строк между двумя указанными адресами.

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

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

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

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


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

awk 1 ORS=' '

объяснение

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

condition { code-block }

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

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

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


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

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

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

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

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


, который должен sed? Вот это bash путь:

cat test.txt |  while read line; do echo -n "$line "; done

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

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

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

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

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

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

три вещи.

  1. tr (или cat, etc.) абсолютно не нужен. (GNU)sed и (GNU)awk, при совмещении, может сделать 99,9% из любой обработки текста вам.

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

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

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

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


tr '\n' ' ' 

команда.

простой и легкий в использовании.


ответ на :этикетку ...

как я могу заменить новую строку (\n) с помощью sed?

... не работает в freebsd 7.2 в командной строке:

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'
foo
bar

но делает, если вы помещаете скрипт sed в файл или используете-e для "сборки" сценария sed...

> (echo foo; echo bar) | sed -e :a -e N -e '$!ba' -e 's/\n/ /g'
foo bar

или ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

возможно, sed в OS X похож.


Я не эксперт, но я думаю, в sed сначала вам нужно добавить следующую строку в пространство шаблонов, bij используя "N". Из раздела "многострочное пространство шаблонов" в разделе "Расширенные команды sed" книги sed & awk (Dale Dougherty and Arnold Robbins; O'Reilly 1997; page 107 in предварительный просмотр):

команда multiline Next (N) создает многострочное пространство шаблонов, считывая новую строку ввода и добавляя ее к содержимому пространства узора. Исходное содержимое пространства шаблонов и новая строка ввода разделяются новой строкой. Внедренный символ новой строки может быть сопоставлен в шаблонах escape-последовательностью "\n". В многострочном пространстве шаблонов метасимвол " ^ " соответствует самому первому символу пространства шаблонов, а не символу(символам) после любой встроенной новой строки(строк). Аналогично, " $ " соответствует только конечной новой строке в пространстве шаблонов, а не какой-либо встроенной новой строке (- ам). После следующей команды выполняется, затем управление передается последующим командам в скрипте.

С man sed:

[2addr] N

добавьте следующую строку ввода в пространство шаблона, используя встроенный символ новой строки, чтобы отделить добавленный материал от исходного содержимого. Обратите внимание, что номер текущей строки изменяется.

Я использовать этот для поиска (нескольких) плохо отформатированных файлов журнала, в которых строка поиска можно найти на" осиротевшей " следующей строке.


простое для понимания решение

у меня была эта проблема. Кикер был в том, что мне нужно было решение для работы над BSD (Mac OS X) и GNU (Linux и Cygwin) sed и tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '0' \
| sed 's:\x00\x00.*:\n:g' \
| tr '0' '\n'

выход:

foo
bar
baz

(имеет пустую строку)

он работает на Linux, OS X и BSD - даже без UTF-8 поддержка или с дерьмовым терминал.

  1. использовать tr чтобы поменять новую строку с другим символом.

    NULL (0 или \x00) приятно, потому что он не нуждается в поддержке UTF-8 и вряд ли будет использоваться.

  2. использовать sed матч NULL

  3. использовать tr чтобы поменять обратно дополнительные новые строки, если они вам нужны


можно использовать xargs:

seq 10 | xargs

или

seq 10 | xargs echo -n

в ответ на решение" tr " выше, в Windows (возможно, используя версию Gnuwin32 tr), предлагаемое решение:

tr '\n' ' ' < input

не работал для меня, это либо ошибка, либо фактически заменить \n w/ " по какой-то причине.

используя другую функцию tr, опция" удалить " - d действительно работала:

tr -d '\n' < input

или '\r\n 'вместо' \n'


я использовал гибридный подход, чтобы обойти новую строку, используя tr для замены новых строк вкладками, а затем заменяя вкладки тем, что я хочу. В данном случае"
" так как я пытаюсь создать разрывы HTML.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

пуленепробиваемое решение. Binary-data-safe и POSIX-совместимый, но медленный.

POSIX sed требует входного сигнала согласно текстовый файл POSIX и POSIX line определения, поэтому NULL-байты и слишком длинные строки не допускаются, и каждая строка должна заканчиваться новой строкой (включая последнюю строку). Это затрудняет использование sed для обработки произвольных входных данных.

следующее решение позволяет избежать sed и вместо этого преобразует входной байты в восьмеричные коды, а затем снова в байты, но перехватывает восьмеричный код 012 (новая строка) и выводит строку замены вместо него. Насколько я могу судить, решение совместимо с POSIX, поэтому оно должно работать на самых разных платформах.

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\$x"; done

справочная документация POSIX: ш, командная оболочка язык, od, tr, grep, читать, [, printf.

и read, [ и printf встроены, по крайней мере, в bash, но это, вероятно, не гарантируется POSIX, поэтому на некоторых платформах может быть, что каждый входной байт запустит один или несколько новых процессов, что замедлит работу. Даже в bash это решение достигает только около 50 кб / с, поэтому оно не подходит для больших файлы.

протестировано на Ubuntu (bash, dash и busybox), FreeBSD и OpenBSD.


в некоторых ситуациях, возможно, вы можете изменить RS к какой-то другой строке или символу. Таким образом, \n доступен для sub/ gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print  }' file

сила сценариев оболочки заключается в том, что если вы не знаете, как это сделать одним способом, вы можете сделать это по-другому. И во многих случаях у вас есть больше вещей, чтобы принять во внимание, чем сделать комплексное решение простой проблемы.

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

я обрабатываю MB и даже GB данных, и единственное ограничение, которое я нашел, - это размер строки.


можно использовать xargs - Это заменить \n с пробелом по умолчанию.

однако, это будет иметь проблемы, если ваш ввод имеет какой-либо случай unterminated quote, например, если знаки цитаты в данной строке не совпадают.


в Mac OS X (с помощью FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta

Использование Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" $0 }  END { print o; }"

решение, которое мне особенно нравится, - это добавить весь файл в пространство хранения и заменить все новые строки в конце файла:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

однако кто-то сказал мне, что пространство удержания может быть конечным в некоторых реализациях sed.


замените новые строки любой строкой и замените последнюю новую строку тоже

чисто tr решения могут заменить только один символ, а чистый sed решения не заменяют последнюю новую строку ввода. Следующее решение устраняет эти проблемы и кажется безопасным для двоичных данных (даже с локали UTF-8):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

результат:

1<br>2<br>3<br>

Это sed что вводит новые строки после "нормальной" замены. Сначала он обрезает символ новой строки, затем обрабатывает его в соответствии с вашими инструкциями, затем вводит новую строку.

используя sed вы можете заменить "конец" строки (не символ новой строки) после обрезки строкой по вашему выбору для каждой входной строки; но,sed выведет различные строки. Например, предположим, что вы хотите заменить "конец строка "with" = = = " (более общая, чем замена одним пробелом):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

чтобы заменить символ новой строки строкой, вы можете неэффективно использовать tr, как указывалось ранее, заменить символы новой строки на "специальный символ", а затем использовать sed чтобы заменить этот специальный символ строкой, которую вы хотите.

например:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$

@OP, если вы хотите заменить новые строки в файле, вы можете просто использовать dos2unix (или unix2dox)

dos2unix yourfile yourfile

удалить пустые строки:

sed -n "s/^$//;t;p;"

вы также можете использовать этот метод

sed 'x;G;1!h;s/\n/ /g;$!d'

объяснение

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
      last line.

расход:
Когда на первой линии вам от входного, обмен производится, поэтому 1 переходит на свободное место и \п доходит до шаблонов, то при добавлении в трюм, чтобы картина пространства, а затем подстановки и удаления шаблонов.
Во время второй линии производится обмен, 2 идет удерживать пространство и 1 приходит в пространство шаблона, то G добавить удерживайте пространство в пространстве шаблона, затем h скопируйте шаблон в него, и подстановка будет сделана и удалена. Эта операция продолжается до EOF достигается затем распечатать точный результат.


еще один GNU sed способ, почти такой же, как Жолтый Botykaiответом, но это использует sedменее часто используется y (транслитерировать) команда, которая спасает один байт кода (трейлинг g):

sed ':a;N;$!ba;y/\n/ /'

надеюсь y будет работать быстрее, чем s, (возможно, на tr скорости, 20x быстрее), но в GNU sed v4.2.2 y о 4% меньше чем s.


портативный BSD sed версия:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'

sed '1h;1!H;$!d
     x;s/\n/ /g' YourFile

это не работает для больших файлов (буфера), но это очень эффективно, если имеется достаточно памяти для хранения файла. (Поправка H ->1h;1!H после хорошего замечания @hilojack)

другая версия, которая изменяет новую строку во время чтения (больше процессора, меньше памяти)

 sed ':loop
 $! N
 s/\n/ /
 t loop' YourFile

я разместил этот ответ, потому что я пробовал с sed commend пример, приведенный выше, который не работает для меня в моем окне Unix и дает мне сообщение об ошибке Label too long: {:q;N;s/\n/ /g;t q}. Наконец, я сделал свое требование и, следовательно, поделился здесь, который работает во всей среде Unix / Linux: -

line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt)
echo $line |sed 's/ //g' > sortedoutput.txt

первая строка удалит всю новую строку из файла yoursourcefile.txt и произведет одиночную линию. И второй sed команда удалит из него все пробелы.