Может ли sed заменить символы новой строки?


43

Есть ли проблема с sed и символом новой строки?
У меня есть файл test.txt со следующим содержимым

aaaaa  
bbbbb  
ccccc  
ddddd  

Следующее не работает:
sed -r -i 's/\n/,/g' test.txt

Я знаю, что могу использовать trдля этого, но мой вопрос, почему это не представляется возможным с помощью sed.

Если это побочный эффект обработки файла строка за строкой, мне было бы интересно, почему это происходит. Я думаю, grepудаляет новые строки. Делает ли sed то же самое?


1
В этом случае sed может быть не лучшим инструментом для использования (например, «tr»). Есть инструменты, которые являются более интуитивными, их легче читать / поддерживать, они работают лучше (особенно на больших данных) и т. Д. ... Не используйте молоток, чтобы вставить винты (даже если он работает). Вы можете найти сравнение на: http://slash4.de/blog/python/sed-replace-newline-or-python-awk-tr-perl-xargs.html
omoser

2
trдобавил бы трейлинг ,и вывел бы неопределенную строку. Лучше всего использовать pasteвместо этого:paste -sd , test.txt
Стефан

Ответы:


50

С GNU sedи при условии POSIXLY_CORRECTне в среде (для однострочного ввода):

sed -i ':a;N;$!ba;s/\n/,/g' test.txt

С https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :

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

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

1
@jim Похоже, что это не в буфере для сопоставления, но я не владею sed, возможно, кто-то еще может пролить свет на это. Я думаю, что вы должны расширить свой Q с этой конкретной информацией, чтобы люди с большей вероятностью прочитали ее и, надеюсь, ответили.
Anthon

Это приводит кba: Event not found
krb686

@ krb686 Что такое «это», на которое вы ссылаетесь? Вы выполнили приведенную выше sedкоманду с этими точными параметрами? На каком test.txt файле? С какой версией sed(попробовать sed --version)?
Антон

@Anthon Извините, думаю, я хотел сказать "the". Я прочитал еще один пост, который сообщил мне, что csh требует от меня избежать !. Интересно, что это все еще не сработало для меня, и я закончил тем, что мне пришлось дважды избегать !в моем .cshсценарии. Так что у меня сейчас нет особых проблем, но вы знаете, почему это может быть? То, что работало для меня, былоsed :a;N;$\\!ba;s/\n/ /g'
krb686

17

Это работает с GNU sed:

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

-z включен с 4.2.2

NB. -zизменяет разделитель на нулевые символы ( \0). Если ваш ввод не содержит нулевых символов, весь ввод рассматривается как одна строка. Это может идти со своими ограничениями .

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

sed -z 's/\n/,/g;s/,$/\n/'

(Что sedснова является синтаксисом GNU , но это не имеет значения, поскольку все это только GNU)


3
Это также заменит завершающий символ новой строки, который может не соответствовать тому, что хочет OP ... сравните результат с решением mikeserv .
don_crissti

7

С веб-сайта Oracle:

Утилита sed работает, последовательно читая файл построчно в память. Затем он выполняет все действия, указанные для строки, и помещает строку обратно в память для выгрузки в терминал с внесенными запрошенными изменениями. После того, как все действия были выполнены с этой одной строкой, он читает следующую строку файла и повторяет процесс, пока не завершится с файлом.

По сути это означает, что поскольку sed читает строку за строкой, символ новой строки не совпадает.

Решение от https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :

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

или в переносной версии (без ;конкатенации после меток меток)

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

Объяснение того, как это работает, приведено на этой странице.


Я использовал модифицированную форму для анализа журналов VPN и размещения «аутентифицированного» пользователя и информации о метках времени в одной строке. Ура!
user208145 25.09.15

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

5

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

Если вы хотите заменить все электронные \nстроки запятыми, а ваш файл не очень большой, то вы можете сделать:

sed 'H;1h;$!d;x;y/\n/,/'

Это добавляет каждую строку ввода к hстарому пробелу - за исключением первого, который вместо этого перезаписывает hстарый пробел - после \nсимвола ewline. Затем он dвыбирает каждую строку, не $!последнюю из выходных данных. В последней строке Hстарые и шаблонные поля заменяются, xи все \nсимволы ewline y///переводятся в запятые.

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


2

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

sed ':a;N;s/\n/,/g;ba'

... просто меняя порядок последовательности.


3
Но запускает sкоманду для каждой строки ввода в пространстве шаблонов, которое становится все больше.
Стефан Шазелас

1

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

GNU говорит это:

Для тех, кто хочет писать переносимые сценарии sed, имейте в виду, что известно, что некоторые реализации ограничивают длину строки (для шаблона и пробелов) не более 4000 байтов. Стандарт posix определяет, что соответствующие sed-реализации должны поддерживать длину строки не менее 8192 байт. GNU sed не имеет встроенного ограничения на длину строки; до тех пор, пока он может malloc () больше (виртуальной) памяти, вы можете кормить или строить строки так долго, как вам нравится.
Однако рекурсия используется для обработки подшаблонов и неопределенного повторения. Это означает, что доступное пространство стека может ограничивать размер буфера, который может обрабатываться определенными шаблонами.

Мне нечего добавить, но я хотел бы указать вам на мое руководство для sed . Это отлично http://www.grymoire.com/Unix/Sed.html

и вот мое решение:

for i in $(cat test.txt); do echo -n $i','; done; echo '' >> somewhere

хорошо это работает



-1

Допустим, вы хотите заменить символы новой строки на \n. Я хотел сделать это, вот что я сделал:

(echo foo; echo bar; echo baz) | sed -r '$!s/$/\\n/' | tr -d '\n' 
# Output: foo\nbar\nbaz

Вот что он делает: для всех строк, кроме последней , добавьте \n. Затем удалите символы новой строки с помощью tr.


-rдоступно только в GNU sed, но не в BSD.
Кенорб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.