Видаліть символ нового рядка лише кожні N рядків


16

Обробляючи текст, мені потрібно видаляти символ нового рядка кожні два рядки.

Приклад тексту:

this is line one
and this is line two
the third and the
fourth must be pasted too

Бажаний вихід:

this is line one and this is line two
the third and the fourth must be pasted too

Я спробував whileцикл, але певний час це погана практика. Чи можливо це зробити за допомогою trбудь-якої іншої команди?


4
У заголовку написано "кожні N рядків", але у запитанні та прикладі це "кожні 2 рядки". Більшість відповідей працюють лише для N = 2. Ви шукаєте щось, що працює для всіх N?
JigglyNaga

Ось ключ. Усі відповідали за 2 рядки, але мені потрібно використовувати N = 3 або N = 4
jomaweb

Відповіді:


24

paste(також стандартна утиліта POSIX на зразок tr) - ваш інструмент для цього.

Припустимо, що ви хочете, щоб ці символи нового рядка замінили пробілом, а не просто видалили, як у вашому зразку:

paste -d ' ' - - < file

Або:

paste -sd ' \n' file

Замінити ' 'з , '\0'якщо ви дійсно хочете , щоб вони були видалені.

Щоб замінити 2 з 3:

paste -sd '  \n' file

1 з 3, починаючи з другого:

paste -sd '\n \n' file

І так далі.

Ще одна гарна річ у pasteтому, що вона не залишить лінію не припиненою. Наприклад, якщо ви видалите кожен новий рядок у файлі (як з tr -d '\n' < fileабо tr '\n' ' ' < file), у вас взагалі немає рядка, оскільки рядки повинні бути завершені символом нового рядка. Тож взагалі краще використовувати pasteзамість цього (як у paste -sd '\0' fileабо paste -sd ' ' file), який додасть, що для нового символу рядка необхідно мати дійсний текст.


11

З сучасним GNU sed

sed -rz 's/\n([^\n]*\n)/ \1/g' sample.text

І awk

awk '{getline line2;print $0, line2}' sample.text

3
Такий sedпідхід означає пригнічувати весь файл у пам’яті (за умови, що він не містить байтів NUL), і виконувати дорогу підстановку на регулярний вираз. Я не бачу переваги над стандартним sed 'N;s/\n/ /'підходом.
Стефан Шазелас

6

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

SHW@SHW:/tmp $ cat a
this is line one
and this is line two
the third and the
fourth must be pasted too

SHW@SHW:/tmp $ sed 'N;s/\n/ /' a -i

SHW@SHW:/tmp $ cat a
this is line one and this is line two
the third and the fourth must be pasted too

4

Іншим способом є використання xargs:

$ < txt xargs -d '\n' -n 2 echo
this is line one and this is line two
the third and the fourth must be pasted too

де

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Хоча це рішення є досить надмірним, оскільки echoвиконується процес для кожного рядка ... Таким чином, крім іграшкових прикладів, слід віддавати перевагу рішенню на основі awk / sed чи подібного.


1
В залежності від вашої echoреалізації, ви також будете мати проблеми зі зворотним косою рисою або кілька рядків , які починаються з -(наприклад , --helpчи -neneз GNU echo). Також зауважте, що -dце розширення GNU.
Стефан Шазелас

Щоб уникнути проблем із цим echo, ви можете скористатися цим:< txt xargs -d '\n' -n 2 printf -- '%s %s\n'
nyuszika7h

4

Це насправді надзвичайно просто in vim. Щоб приєднатись до кожного рядка, використовуйте Jкоманду, а потім використовуйте%norm командою, щоб застосувати його до кожного рядка одночасно. Наприклад

:%norm J<CR>

(Про всяк випадок, якщо ви не знайомі з vim, <CR>просто означає ввести)

Це навіть працює, щоб приєднати довільну кількість рядків. Наприклад, приєднуватися кожні десять рядків було б

:%norm 9J<CR>

Якщо вам не подобається vim, і ви вважаєте за краще використовувати його як інструмент командного рядка, а не інтерактивний текстовий редактор:

vim myfile -c '%norm J' -c 'wq'

Чи хотів би ревізор пояснити, що я можу зробити, щоб покращити цю відповідь?
DJMcMayhem

3
$ awk '{printf "%s%s",$0,(NR%2?" ":"\n")}' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Це друкує кожен рядок, $0після чого пробіл або новий рядок, залежно від того, номер рядка,NR непарний або парний.

Вираз NR%2?" ":"\n"є потрійним твердженням. ВиразNR%2 оцінюється як true (ненульовий), якщо число рядка непарне. У випадку, потрійний вираз повертає пробіл. Якщо він оцінюється як false (нуль), то повертається новий рядок.

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

Як запропонував Костас у коментарях:

$ awk '{ORS=(NR%2?" ":RS)}1' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Тут потрійний оператор NR%2?" ":RSвикористовується для повернення або пробілу, або роздільника вхідних записів ( RS, за замовчуванням = новий рядок). Це значення присвоюється роздільник записів виведення, ORS. В 1кінці команди - це криптовальна стенда awk для друку-запису.


Ви можете зберегти 3 символи: ()дужки та пробіл після printf;)
maxschlepzig

1
Трійця? Ой! 'NR%2{printf("%s ",$0);next}1'
Костас

З відповіддю maxschlepzig та потрійною заявою:'{ORS=(NR%2?" ":RS)}1'
Costas

@Costas мені це подобається. Відповідь оновлено ORSрішенням.
John1024

2

Загальне рішення, замініть 5на кількість необхідних ліній

$ # eof to ensure last line has newline ending
$ seq 16 | perl -pe 's/\n/ / if ++$i%5 && !eof'
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

$ # or just use pr
$ seq 16 | pr -5ats' '
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

1

Ви можете використовувати awkдля цього:

$ awk '{c="\n"} NR%2 {c=" "} { printf("%s%s", $0, c) } ' txt

Він виробляє:

this is line one and this is line two
the third and the fourth must be pasted too

де:

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Ці awkдії виконуються для кожного рядка, спеціальні змінні $0посилання на поточний рядок, NRце номер поточного рядка (починаючи з 1). Друга дія захищається виразом NR%2, який є операцією модуля. Таким чином, c=" "виконується лише в тому випадку, коли NR%2це правда, тобто для непарних номерів рядків.

awkСинтаксис C , як, але деякі елементи НЕ є обов'язковими в деяких контекстах - наприклад , точка з коми.


Ваша cзмінна ORS:'NR%2{ORS=" "}1;{ORS=RS}'
Costas

0

Використання ed:

$ cat text
this is line one
and this is line two
the third and the
fourth must be pasted too
this is line one
and this is line two
the third and the
fourth must be pasted too

$ ed text <<'END_ED'
g/./s/$/ /\
j
w text.new
END_ED
164
164

$ cat text.new
this is line one and this is line two
the third and the fourth must be pasted too
this is line one and this is line two
the third and the fourth must be pasted too

Команди edредагування для кожного рядка ( gзастосовує набір команд редагування до кожного рядка, що відповідає заданому регулярному виразу) додають пробіл до кінця та з'єднують його з наступним рядком. Потім він записує отриманий текст у файл, який називається text.new.


0

З Рубі.

Я припускаю, що кожен блок nрядків повинен бути з'єднаний. Припустимо n = 3, вхідний файл є, 'infile'а результати потрібно записувати у файл 'outfile'.

Побудувати файл

Ruby -e "File.write 'infile', <<_
> Line 1
> Line 2
> Line 3
> Line 4
> Line 5
> Line 6
> Line 7
> _"

Підтвердьте вміст файлу

ruby -e "p File.read 'infile'"
  # "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\n"

Видаліть нові рядки та запишіть у файл

ruby -e "File.write 'outfile', File.readlines('infile').
  each_with_index { |line,i| line.chomp! unless (i+1)%3==0 }"

Підтвердьте вміст

ruby -e "puts File.read 'outfile'"
  # ["Line 1", "Line 2", "Line 3\n", "Line 4", "Line 5", "Line 6\n", "Line 7"]

1
Хороший. Теоретично rubyце поза темою U&L. Але, оскільки ви використовуєте його з командного рядка з ruby -e, це робить його досить тематичним.
grochmal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.