Як можна замінити новий рядок (\ n) за допомогою sed?


1370

Як я можу замінити новий рядок (" \n") пробілом (" ") за допомогою sedкоманди?

Я безуспішно намагався:

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

Як це виправити?


27
trє лише правильним інструментом для роботи, якщо замінити один символ на один символ, тоді як приклад вище показаний заміни нового рядка пробілом .. Отже, у наведеному вище прикладі tr може працювати .. Але обмежуватиметься згодом.
Злий 84

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

3
"tr" також може просто видалити новий рядок `tr -d '\ n' ', однак ви також можете хотіти видалити повернення, щоб бути більш універсальним` tr -d' \ 012 \ 015 ''.
антоній

2
ПОПЕРЕДЖЕННЯ: "tr" діє по-різному щодо діапазону символів між Linux та старими машинами Solaris (EG sol5.8). EG: `tr -d 'az'` і `tr -d '[az]'`. Для цього я рекомендую вам використовувати "sed", який не має такої різниці.
Антоній

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

Відповіді:


1513

Використовуйте це рішення з 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 and Masi: OS X використовує BSD, sedа не GNU sed, тому можуть бути деякі тонкі (а деякі не такі тонкі) відмінності в двох. Це постійний біль, якщо ви працюєте як на машинах OS X, так і на * nix. Зазвичай я встановлюю GNU coreutilsі findutilsна OS X і ігнорую версії BSD.
Телемах

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

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

74
Чому ніхто не коментує, який це німий безлад (не сама відповідь, а програма, на яку запропонована відповідь - найкраще рішення дуже простої проблеми). Sed виглядає як машина, яка зазвичай працює нормально, але якщо ви хочете їхати на конкретну сусідню вулицю, єдиний спосіб - підняти машину вертольотом.
Арк-кун

12
Давайте, люди - 261 грошей за божевільне, незрозуміле рішення, яке не працює ???? sed - чудовий інструмент для простого заміщення на одній лінії, для всього іншого просто використовуйте awk. Добре горе ....
Ед Мортон

1711

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 чудово, але ви можете замінити нові рядки лише окремими символами. Вам потрібно використовувати інший інструмент, якщо ви хочете замінити рядки рядком
Едді,

21
@Eddy - я використовував tr для заміни нових рядків символом, який не відображався в тексті (я використовував backtick), потім sed замінював
backtick

494

Швидка відповідь

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 -p -e 's/\n/ /' file

з tr , швидше, ніж sed , може замінюватися лише одним символом

tr '\n' ' ' < file

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

paste -s -d ' ' file

з awk , tr- подібною швидкістю

awk 1 ORS=' ' file

Інша альтернатива, наприклад "echo $ (<файл)" повільна, працює лише на невеликих файлах і для початку процесу потрібно обробити весь файл.


Довга відповідь від sed FAQ FAQ 5.10

5.10. Чому я не можу зіставити чи видалити новий рядок, використовуючи \ 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
("Як видалити блок певних послідовних рядків?"). Цей
приклад можна змінити, змінивши команду delete на щось
інше, наприклад, "p" (друк), "i" (вставити), "c" (змінити), "a" (додати)
або "s" (замінити) .

Вибір (3) не покладе \ п в просторі картини, але це дійсно
відповідає блок послідовних ліній, так що це може бути , що ви не
навіть потребуєте \ п , щоб знайти те , що ви шукаєте. Оскільки GNU sed
версія 3.02.80 тепер підтримує цей синтаксис:

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

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


6
trбула чудовою ідеєю, і ваше загальне покриття дає відповідь на найвищу якість.
Нова Олександрія

1
+1 за користування ( стандартна утиліта ) paste... та всі інші!
Тотор

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

4
Найкраща частина цієї відповіді полягає в тому, що "довга відповідь" пояснює, як саме і чому працює команда.
pdwalker

3
Це може бути найбільш корисним з тисяч відповідей, які я прочитав на stackexchange. Мені потрібно зіставити кілька символів по рядках. Жоден попередній приклад седу не охоплював багато рядків, а тр не може обробляти відповідність кількох символів. Perl виглядає добре, але не працює, як я очікував. Я би проголосував за цю відповідь кілька разів, якби міг.
могучий

225

Коротша альтернатива awk:

awk 1 ORS=' '

Пояснення

Програма awk складається з правил, які складаються з умовних блоків коду, тобто:

condition { code-block }

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

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

Тепер, коли друкується запис, ORSдо нього додається (Output Record Separator), за замовчуванням знову є новий рядок. Отже, змінюючи 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"} '
michael

2
Ви можете зробити це більш просто: codeawk 'ORS = ""' file.txtcode
Udi

При використанні подібного awk тоді, на жаль, видаляється також останній рядок у файлі. Дивіться відповідь Патріка Темного вище про використання "tr" в підрозділі типу "cat file |" echo $ (tr "\ 012" "") `що робить трюк. Ніфт.
Bernie Reiter

143

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

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

4
Навіть якщо вхід містить нулі, вони будуть збережені (як роздільники записів).
Toby Speight

6
Чи не буде це завантаження всього входу, якщо немає нулів? У цьому випадку обробка багатогігабайтного файлу може бути збійною.
Руслан

3
@Ruslan, так, він завантажує весь вхід. Це рішення не є хорошою ідеєю для файлів з багато гігабайт.
JJoao

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 у питанні про ОП не створює резервного копіювання, тому тут здається зайвим. Інша причина полягає в тому, що я ніколи фактично не використовував функцію резервного копіювання (я вважаю, що автоматичні резервні копії насправді дратують), тому я завжди забуваю, що він є. Третя причина - це робить мій командний рядок на чотири символи довшим. На краще чи гірше (напевно, гірше) я нав'язливий мінімаліст; Я просто віддаю перевагу стислість. Я розумію, ти не згоден. Я постараюся зробити все можливе, щоб пам'ятати, щоб попередити про створення резервних копій у майбутньому.
ire_and_curses

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

Це дуже прикро, що це не працює зі 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
Оновлення, як правило, я використовував верхню відповідь, але при прокладанні / dev / urandom через нього sed не надрукує, поки не буде EOF, а ^ C - не EOF. Це рішення друкується кожного разу, коли він бачить новий рядок. Саме те, що мені було потрібно! Дякую!
Василь Шарапов

1
то чому б і ні: відлуння -n `котячі дні.txt` З цього повідомлення
Тоні,

9
@Тоні тому, що backticks застарілий, а кішка зайва ;-) Використання: 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тощо) абсолютно не потрібні. (GNU) sedта (GNU) awkпри їх поєднанні можуть виконати 99,9% будь-якої необхідної для обробки тексту.

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

  3. Це сумно,

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

    добре працює у sedверсії 4.2.1 GNU . Наведена вище команда замінить усі нові рядки пробілами. Це некрасиво і трохи громіздко вводити, але це працює чудово. Це {}може бути залишене, оскільки вони включені лише з міркувань безпеки.


3
Як людина, яка знає лише достатньо, sedщоб робити основні речі, я мушу сказати, що це більше, ніж про те, що ви можете зробити, sedа навпаки, як легко зрозуміти, що відбувається. У мене дуже важко працювати, sedтому я вважаю за краще простішу команду, коли можу її використовувати.
Нейт

Використовуючи t qяк умовний стрибок, це працює з таким малюнком s/\n / /(щоб з'єднати всі рядки, які починаються з пробілу), не читаючи весь файл у пам'яті. Зручно під час трансформації файлів у багато мегабайт.
texthell

Стаття, яку ви пов’язали, не відображає те, що ви говорите
hek2mgl

Це майже в 800 разів повільніше, ніж прийнята відповідь на великому вкладі. Це пов’язано із запуском заміни кожного рядка на все більшому введенні.
Тор

13

Відповідь: етикетка ...

Як можна замінити новий рядок (\ n) за допомогою sed?

... не працює у freebsd 7.2 у командному рядку:

(відлуння; echo bar) | 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; ехо-бар) | 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 схожий.


Серія аргументів -e працювала для мене на Windows за допомогою 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 ++).
sqweek


9

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

Команда Multiline Next (N) створює багаторядковий простір шаблону, читаючи новий рядок введення та додаючи його до вмісту простору шаблону. Початковий вміст простору шаблону та новий рядок введення розділені новим рядком. Вбудований символ нового рядка може бути узгоджений у шаблонах послідовністю виходу "\ n". У просторі з мультилінійним шаблоном метахарактер "^" відповідає першому символу простору шаблону, а не символу (ів) після будь-яких вбудованих нових рядків. Аналогічно, "$" відповідає лише остаточному новому рядку в просторі шаблону, а не будь-якому вбудованому новому рядку. Після виконання команди Next керування передається наступним командам у сценарії.

Від man sed:

[2ддр] N

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

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


7

Я використовував гібридний підхід, щоб обійти річ нового рядка, використовуючи tr для заміни нових рядків на вкладки, а потім замінивши вкладки на те, що я хочу. У цьому випадку "
", оскільки я намагаюся генерувати HTML-перерви.

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

6

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

tr '\n' ' ' < input

не працював для мене, він або помилився, або фактично замінив \ nw / '' чомусь.

Використовуючи ще одну функцію tr, параметр "delete" -d працював, хоча:

tr -d '\n' < input

або '\ r \ n' замість '\ n'


3
У Windows, ймовірно, потрібно використовувати tr "\n" " " < input. Оболонка Windows (cmd.exe) не розглядає апостроф як котируючий символ.
Кіт Томпсон

Ні, в підсистемі Windows 10 Ubuntu потрібно використовувати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вбудовані принаймні в баш, але це, можливо, не гарантується POSIX, тому на деяких платформах може бути так, що кожен вхідний байт запустить один або кілька нових процесів, що сповільнить роботу. Навіть у bash це рішення досягає лише 50 кБ / с, тому воно не підходить для великих файлів.

Тестовано на Ubuntu (bash, dash і busybox), FreeBSD та OpenBSD.


5

У деяких ситуаціях, можливо, ви можете перейти RSна інший рядок або символ. Таким чином, \ n доступний для sub / gsub:

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

Сила сценаріїв оболонок полягає в тому, що якщо ви не знаєте, як це зробити одним способом, ви можете зробити це іншим способом. І багато разів вам доводиться брати до уваги більше речей, ніж складати комплексне рішення простої проблеми.

Щодо того, що 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розумієте це позначення зворотної косої риски).
трійка

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
Вам не потрібно уникати лапок і знака долара, якщо ви зміните зовнішні на одиничні. Буква "o" зазвичай вважається поганим вибором як ім'я змінної, оскільки її можна переплутати з цифрою "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}
Jeff

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>

Це погано, оскільки він дасть небажаний вихід на будь-який вхід, що містить@
Стівен Лу,

@StevenLu: Ні, @у вводі все нормально. Він знову втече %aі повертається назад. Рішення може бути не повністю сумісним з POSIX (хоча NULL-байти не дозволені, тому не добре для бінарних даних, і всі рядки повинні закінчуватися новим рядком, щоб trвихід не був дійсним).
Håkon A. Hjortland

Ага. Я бачу, ви це виправили. Свого роду переконання в тому, що це повинна бути проста операція, але хороша робота.
Стівен Лу

3

Саме sed вводить нові рядки після "нормальної" заміни. Спочатку вона обрізає новий рядок char, потім обробляє згідно з вашими вказівками, потім вводить новий рядок.

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

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

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

Щоб замінити новий рядок char на рядок, ви можете, неефективно, використовувати tr , як було зазначено раніше, замінити символи нового рядка на "спеціальний знак", а потім використовувати sed щоб замінити цей спеціальний char на потрібну рядок .

Наприклад:

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

Інший ГНУ sed метод, майже такий же , як Жолт Botykai «відповідь s , але це використовує sed» менш часто використовується з y( Transliterate команда), що економить один байт коду (трейлинг g):

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

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


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

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

2
З BSD sed на y15% швидше. Дивіться цю відповідь на робочому прикладі.
Тор

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