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


1372

Как заменить новую строку (" \n") пробелом (" ") с помощью sedкоманды?

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

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

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


27
trявляется только правильным инструментом для задания, если заменить один символ для одного символа, в то время как в приведенном выше примере показано заменить символ новой строки пробелом. Так что в приведенном выше примере tr может работать .. Но будет ограничение позже.
Злой 84

9
trв правильном инструменте для работы, потому что спрашивающий хотел заменить каждую новую строку пробелом, как показано в его примере. Замена новых строк уникальна, sedно легко выполняется tr. Это общий вопрос. Выполнение замены регулярных выражений выполняется не с помощью, trа с sedпомощью подходящего инструмента ... для другого вопроса.
Майк С

3
«tr» также может просто удалить символ новой строки «tr -d» \ n », однако вы также можете удалить возврат, чтобы сделать его более универсальным« tr-d »\ 012 \ 015».
Энтони

2
ВНИМАНИЕ: «tr» действует по-разному в отношении диапазонов символов между Linux и более старыми машинами Solaris (EG sol5.8). Например: `tr -d 'az'` и `tr -d '[az]'`. Для этого я рекомендую вам использовать «sed», который не имеет такой разницы.
Энтони

2
@MikeS Спасибо за ответ. Следуйте tr '\012' ' 'с echo. В противном случае также будет удален последний перевод строки в файле. tr '\012' ' ' < filename; echoделает трюк.
Берни Райтер

Ответы:


1514

Используйте это решение с 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этой простой проблемы проблематично. Для более простого и адекватного решения см. Этот ответ .


45
@Arjan и Masi: OS X использует BSD, sedа не GNU sed, поэтому между ними могут быть некоторые тонкие (а некоторые и не очень) различия. Это постоянная боль, если вы работаете на компьютерах с OS X и * nix. Я обычно устанавливаю GNU coreutilsи findutilsна OS X и игнорирую версии BSD.
Телемах

50
Это :aне регистр, это метка филиала. Это цель для bкоманды *, которая работает как "goto". Называя его регистром, вы можете создавать места для хранения. Есть только два «регистра»; один называется «пространством удержания», которое не используется вашим сценарием, а другой - «пространством шаблона». Команда Nдобавляет новую строку и и следующую строку входного файла в пространство шаблона. [* Вы можете иметь несколько меток и bкоманд. Если у вас есть bкоманда без добавленной к ней метки char, она переходит к концу сценария, чтобы прочитать следующую строку и повторить цикл.]
Пауза до дальнейшего уведомления.

108
Вы можете запустить эту кроссплатформенную платформу (т.е. в Mac OS X), выполняя команды отдельно, а не разделяя их точкой с запятой: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie

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

12
Давай, ребята - 261 голосов за сумасшедшее, непонятное решение, которое не работает ???? sed - отличный инструмент для простых замен в одной строке, для всего остального просто используйте awk. Хорошее горе ....
Эд Мортон

1712

sedпредназначен для использования на линейном вводе. Хотя он может делать то, что вам нужно.


Лучшим вариантом здесь является использование trкоманды следующим образом:

tr '\n' ' ' < input_filename

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

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

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

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

88
Sed основан на строках, поэтому ему трудно понять новые строки.
Александр Гладыш

191
sed работает с «потоком» ввода, но понимает его в разделенных строкой. Это инструмент Unix, что означает, что он делает одну вещь очень хорошо. Одна вещь - это «работа над файлом по строкам». Заставить его сделать что-то еще будет сложно, и это может привести к ошибкам. Мораль этой истории такова: выберите правильный инструмент. Очень многие ваши вопросы, кажется, принимают форму «Как я могу заставить этот инструмент делать то, чего он никогда не должен был делать?» Эти вопросы интересны, но если они возникают в процессе решения реальной проблемы, вы, вероятно, делаете это неправильно.
dmckee --- котенок экс-модератора

7
@JBBrown tr- часто пропускаемая жемчужина для строительства трубопроводов.
dmckee --- котенок экс-модератора

70
tr отлично, но вы можете заменить только новые строки одиночными символами. Вам нужно использовать другой инструмент, если вы хотите заменить символы новой строки на строку
Eddy

21
@ Eddy - я использовал tr, чтобы заменить новые строки символом, которого нет в тексте (я использовал backtick), а затем sed, чтобы заменить backtick строкой, которую я хотел использовать
rjohnston

494

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

sed ':a;N;$!ba;s/\n/ /g' file
  1. : создать ярлык «а»
  2. N добавить следующую строку в пространство образца
  3. $! если не в последней строке , ба ветвь (перейти к) метка «а»
  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- like speed, может заменить только один символ

paste -s -d ' ' file

с awk , tr- like скоростью

awk 1 ORS=' ' file

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


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

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

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

Sed работает следующим образом: sed читает по одной строке за раз, отсекает
завершающую новую строку , помещает то, что осталось, в пространство шаблона, где
сценарий sed может обратиться или изменить его, а когда пространство шаблона
печатается, добавляет новую строку в 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, имеют ограничения по размеру
буфера шаблонов, здесь предпочтительнее использовать утилиту «tr» Unix.
Если последняя строка файла содержит новую строку, GNU sed добавит
эту новую строку в вывод, но удалит все остальные, тогда как tr
удалит все новые строки.

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

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

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

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

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


6
trбыла отличная идея, и ваш общий охват дает качественный ответ.
Новая Александрия

1
+1 за использование ( стандартная утилита ) paste... и все остальные!
Тотор

1
@elgalu попробуйте это unix.stackexchange.com/questions/4527/…
hdorio

4
Лучшая часть этого ответа состоит в том, что «длинный ответ» объясняет, как именно и почему команда работает.
pdwalker

3
Это может быть самым полезным из тысяч ответов, которые я прочитал на stackexchange. Мне нужно сопоставить несколько символов в разных строках. Ни один из предыдущих примеров sed не содержал многострочных символов, и tr не может обработать сопоставление нескольких символов. Perl выглядит хорошо, но не работает, как я ожидаю. Я бы проголосовал за этот ответ несколько раз, если бы мог.
могучий

225

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

awk 1 ORS=' '

объяснение

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

condition { code-block }

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

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

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


5
Мне очень нравится это простое решение, которое гораздо более читабельно, чем другие
Федир РИХТИК

8
Если это имеет больше смысла, это может быть эффективно записано как: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(добавление завершающего символа новой строки только для иллюстрации начала / конца); «1» оценивает true(обработать строку) и print(вывести строку). К этому выражению также можно добавить условное выражение, например, работать только со строками, соответствующими шаблону: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
майкл

2
Вы можете сделать это более просто: codeawk 'ORS = ""' file.txtcode
Udi

При использовании awk, подобного этому, к сожалению, также удаляется последний перевод строки в файле. Смотрите ответ Патрика Дарк выше об использовании 'tr' в подоболочке вроде `cat file | echo $ (tr "\ 012" "") `, который добивается цели. Острота.
Берни Рейтер

143

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

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

4
Даже если входные данные содержат нули, они будут сохранены (как разделители записей).
Тоби Спейт

6
Разве это не загрузит весь ввод, если нет нулей? В этом случае обработка файла объемом в несколько гигабайт может привести к сбою.
Руслан

3
@Ruslan, да, он загружает весь ввод. Это решение не очень хорошая идея для мультигигабайтных файлов.
Жоао

7
Это серьезно лучший ответ. Другие выражения слишком искажены, чтобы их запомнить. @JJoao Вы можете использовать его с -u, --unbuffered. В manмаге говорится: «нагрузить минимальное количество данных из входных файлов и сбрасывайте выходные буфера чаще».
not2qubit

так. много. это.
Sjas

85

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

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

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


23
Пожалуйста, по крайней мере, отметьте, что -iбез суффикса не делается резервная копия . -i.bakзащищает вас от простой, уродливой ошибки (скажем, забыв набрать -pи обнулить файл).
Телемах

6
@Telemachus: Это справедливо, но с этим можно поспорить в любом случае. Основная причина, по которой я не упомянул это, заключается в том, что пример sed в вопросе OP не создает резервных копий, поэтому здесь он кажется излишним. Другая причина в том, что я никогда не использовал функции резервного копирования (автоматические резервные копии меня раздражают), поэтому я всегда забываю, что они есть. Третья причина - это делает мою командную строку на четыре символа длиннее. Лучше или хуже (возможно, хуже), я навязчивый минималист; Я просто предпочитаю краткость. Я понимаю, что вы не согласны. Я буду стараться изо всех сил помнить, чтобы предупредить о резервных копиях в будущем.
ire_and_curses

6
@Ire_and_curses: На самом деле, вы только что сделали чертовски хороший аргумент за игнорирование меня. То есть у вас есть причины для вашего выбора, и я согласен с тем, согласен я или нет с этим выбором. Я не совсем уверен, почему, но я был в слезах по поводу этой конкретной вещи ( -iфлаг в Perl без суффикса). Я уверен, что скоро найду что-нибудь еще, чем можно заняться. :)
Телемах

Очень жаль, что это не работает с stdin, указав -имя файла. Есть способ сделать это? Мой способ не беспокоиться об изменении файла - использовать конвейер, который начинается с cat.
Стивен Лу

@StevenLu Perl будет читать из STDIN по умолчанию, если не указано имя файла. Так что вы можете сделать, например,perl -i -p -e 's/\n//' < infile > outfile
ire_and_curses

44

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

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

2
Upvote, я обычно использовал верхний ответ, но при прохождении через него / dev / urandom, sed не будет печататься до EOF, а ^ C не будет EOF. Это решение печатает каждый раз, когда видит новую строку. Именно то, что мне было нужно! Спасибо!
Василий Шарапов

1
тогда почему бы и нет: echo -n `cat days.txt` Из этого поста
Тони

9
@ Тони, потому что обратные пометки устарели, а кот избыточен ;-) Использование: echo $ (<days.txt)
seumasmac

10
Даже не используя cat: while read line; do echo -n "$line "; done < test.txt. Может быть полезно, если проблема связана с вложенной оболочкой.
Карло Каннас

5
echo $(<file)сжимает все пробелы в один пробел, а не только в новые строки: это выходит за рамки того, что просит ОП.
Гленн Джекман

27

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

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

Если вы хотите последний перевод строки:

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

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

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

END{ print ""}это более короткая альтернатива для новой строки.
Исаак

22
tr '\n' ' ' 

это команда.

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


14
или просто, tr -d '\n'если вы не хотите добавлять пробел
spuder

21

Три вещи.

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

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

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

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

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


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

При использовании в t qкачестве условного перехода это работает с шаблоном типа s/\n / /(чтобы объединить все строки, начинающиеся с пробела) без чтения всего файла в память. Удобно при преобразовании мультимегабайтных файлов.
текстовая оболочка


Это почти в 800 раз медленнее, чем принятый ответ на большом входе. Это связано с выполнением замены для каждой строки на все большем вводе.
Тор

13

Ответ с меткой ...

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

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

(эхо фу; эхо бар) | sed ': a; N; $! ba; s / \ n / / g'
sed: 1: ": a; N; $! ba; s / \ n / / g": неиспользуемая метка 'a; N; $! ba; s / \ n / / g'
Foo
бар

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

> (echo foo; echo bar) | sed -e: -e N -e '$! ba' -e 's / \ n / / g'
фу бар

или ...

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

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

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


Ряд аргументов -e работал для меня на окнах, используя MKS! Спасибо!
JamesG

12

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

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

$ echo 'foo
bar
baz


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

Вывод:

foo
bar
baz

(завершающий перевод строки)

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

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

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

  2. использование sed чтобы соответствоватьNULL

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


1
Тонкое замечание по номенклатуре: символ \000обычно упоминается как NUL(один L) и NULLобычно используется, когда речь идет о нулевом указателе (в C / C ++).
Квадрат


9

Я не эксперт, но я думаю sed, что сначала вам нужно добавить следующую строку в пространство шаблонов, используя " N". Из раздела «Пространство многострочных шаблонов» в «Расширенных командах sed» книги sed & awk (Дейл Догерти и Арнольд Роббинс; О'Рейли, 1997 год; стр. 107 в превью ):

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

От man sed:

[2addr] Н

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

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


7

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

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

6

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

tr '\n' ' ' < input

не работал для меня, он либо по ошибке, либо фактически заменил \ nw / '' по какой-то причине.

Используя другую функцию tr, опция -d «delete» сработала:

tr -d '\n' < input

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


3
В Windows вам, вероятно, нужно использовать tr "\n" " " < input. Оболочка Windows (cmd.exe) не рассматривает апостроф как символ цитирования.
Кит Томпсон

Нет, в подсистеме Ubuntu Windows 10 вам нужно использоватьtr "\n\r" " " < input.txt > output.txt
user1491819

Это работает на Windows 10 с помощью gnuwin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Или вместо Gnuwin32 используйте Gow (Gnu в Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt

5

Пуленепробиваемое решение. Бинарные данные безопасны и POSIX-совместимы, но медленно.

POSIX SED требует ввода в соответствии с текстовым файлом POSIX и POSIX линии определениями , поэтому 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: sh , язык команд оболочки , od , tr , grep , read , [ , printf .

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

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


5

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

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

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

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

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


5

Если вам не повезло иметь дело с окончаниями строк Windows, вам нужно удалить \rи\n

tr '[\r\n]' ' ' < $input > $output

Это заменяет [пробелом, \rпробелом, \nпробелом и ]пробелом. tr -d '\r\n' <fileудалит любой \rили \nсимволы, но это также не то, что спрашивают. tr -d '\r' <fileудалит любые \rсимволы (независимо от того, являются ли они смежными \n), что, вероятно, ближе к тому, чтобы быть полезным, а также вполне возможно, корректно для нужд ОП (при условии, что вы trпонимаете эту запись с обратной косой чертой).
tripleee

4

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

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


xargs также хорошо обрабатывает последнюю строку:
AAAfarmclub

4

Находит и заменяет с помощью разрешения \ n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

маркер

становится

# Маркерный комментарий

маркер


4

Почему я не нашел простого решения с awk?

awk '{printf $0}' file

printf напечатает каждую строку без перевода строки, если вы хотите отделить исходные строки пробелом или другим:

awk '{printf $0 " "}' file

echo "1\n2\n3" | awk '{printf $0}'это работает для меня. @ edi9999
Итачи

Вы правы, извините, я забыл fв printf
edi9999

это был единственный подход, который работал для меня в Git Bash для Windows
Платон

3

В 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


3

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

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

2
Вам не нужно избегать кавычек и знака доллара, если вы измените внешние на одинарные кавычки. Буква «о» обычно считается неправильным выбором в качестве имени переменной, поскольку ее можно спутать с цифрой «0». Вам также не нужно инициализировать вашу переменную, по умолчанию это пустая строка. Однако, если вы не хотите , постороннюю ведущее место: awk '{s = s sp $0; sp = " "} END {print s}'. Однако, смотрите мой ответ, чтобы узнать, как использовать awk без чтения всего файла в память.
Приостановлено до дальнейшего уведомления.

Пожалуйста, проверьте ответ Тора вместо этого. Это способ более эффективна, читаемый и просто лучше все средства по сравнению такого подход (даже если это будет работать)!
mschilli

Чувак, я понял. Не нужно втирать мне в лицо :-) В любом случае, ответ Тора на странице выше (что правильно), так что вас волнует?
kralyk

3

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

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

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


1
замена пустой строкой в ​​вашем ответе скрывает тот факт, что всегда добавление H к пробелу означает, что пробел будет начинаться с новой строки. Чтобы этого избежать, нужно использовать1h;2,$H;${x;s/\n/x/g;p}
Джефф

3

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

Чистые 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>

Это плохо, потому что он будет выдавать нежелательный вывод на любом входе, содержащем@
Steven Lu

@ StevenLu: Нет, @на входе все в порядке. Это сбежало туда %aи обратно. Однако решение может быть не полностью совместимым с POSIX (NULL-байты недопустимы, поэтому не годятся для двоичных данных, и все строки должны заканчиваться символом новой строки, поэтому trвывод не является действительным).
Хокон А. Хьортланд

Ах. Я вижу, вы исправили это. В некотором роде извилистые для того, что должно быть простая операция, но хорошая работа.
Стивен Лу

3

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

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

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~$

3

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

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 переходит в пространство пробелов, а \ n переходит в пространство шаблонов, затем добавляется пространство удержаний в пространство шаблонов, затем выполняется подстановка и удаляется пространство шаблонов.
Во время обмена второй строкой 2 переходит в область пробелов, а 1 переходит в пространство паттернов, затем Gдобавляет пространство удержаний в пространство паттернов, затем hкопирует в него паттерн, и подстановка выполняется и удаляется. Эта операция продолжается до тех пор, пока eof не будет достигнут, затем выведите точный результат.


Тем не менее, имейте в виду, что в echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'результате XY.
жуткий

3

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

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

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


Более портативная версия BSD sed :

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

2
С BSD sed yпримерно на 15% быстрее. Смотрите этот ответ для рабочего примера.
Тор

Кроме того, с BSD команды sed должны завершаться после метки, так sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'что это будет путь.
Готи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.