Чи може sed видалити "подвійні" символи нового рядка?


25

У мене документ з великою кількістю порожніх рядків.

Як їх видалити, коли разом є 2 або більше.

Я спробував sed "s/\n\n//"файл, але нічого не вийшло. Немає помилок.


3
Чи правильно я вас читаю, якщо ви не хочете видаляти всі порожні рядки, але лише якщо їх два чи більше. Тож не поодинокі порожні рядки?
Руніум

1
І якщо це два або більше рядків, чи справді всі вони будуть видалені або просто всі, крім одного?
Хоуке Лагінг

Відповіді:


42

Просто для видалення порожніх рядків:

sed  '/^$/d'

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


Звичайно! +1 для простої елегантності.
тердон

2
sedздатний обробляти декілька ліній за допомогою функції "простір візерунка" / "простір утримувати". Але я відчуваю, що це занадто складно. ;-)
Хоуке Лагінг

Це не буде функціонувати за бажанням, якщо перший символ файлу є новим рядком.
Кріс Даун

1
Для того, щоб змусити його працювати , коли перший символ нового рядка (якщо це дійсно вимога), то ви можете зробити висновок команду з негативним адресою 1!(відповідає всім , крім рядка 1), таким чином: sed '1!{/^$/d'}.
Toby Speight

1
@AaronFranke - так, але це аспект того, як оболонки Linux ставляться до перенаправлення '>'. Оболонка дивиться на командний рядок, бачить перенаправлення stdout до файлу '>', створює цей файл і лише після цього запускається sed. Створення файлу фактично видалить будь-який існуючий файл з тим самим іменем. sed '/^&/d' file.txt > otherfile.txtбуду працювати.
Брюс Едігер

24

Не потрібно sed. grepзроблю:

grep .

(тобто grepSPC, крапка, тобто відповідність будь-якій лінії, що містить принаймні один символ).

Також є:

tr -s '\n'

(видавити будь-яку послідовність символів нового рядка в одну).

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


2
Це не буде функціонувати за бажанням, якщо перший символ файлу буде новим
Chris Down

7

sedне найкращий інструмент для цього, оскільки він заснований на рядках і трактується \nяк символ кінця рядка, але це ускладнюється.Побачивши @Bruce Ediger в відповідь sed цілком може бути ідеальним інструментом для роботи, до сих пір, ось деякі інші варіанти:

  1. Perl

    perl -ne 'print if /./' file.txt
    

    або

    perl -pe '$/=""; s/\n+/\n/;' file.txt 
    

    Дякую @ruakh, який змусив мене піти і прочитати це :

    $ /

    Розділювач вхідних записів, новий рядок за замовчуванням. Це впливає на уявлення Перла про те, що таке "лінія". Працює як RS змінна RS, включаючи трактування порожніх рядків як термінатора, якщо встановлено нульовий рядок (порожній рядок не може містити пробілів чи вкладок). Ви можете встановити його на багато символьну рядок, щоб відповідати багато символьному термінатору, або undef для читання в кінці файлу. Установити його на "\ n \ n" означає щось трохи інше, ніж встановити значення "", якщо файл містить послідовні порожні рядки. Якщо встановити "", два чи більше послідовних порожніх рядків будуть розглядатись як один порожній рядок. Якщо встановити "\ n \ n", сліпо буде вважати, що наступний символ введення належить до наступного абзацу, навіть якщо це новий рядок.

  2. гаук / awk

    awk '$1' file.txt
    

    Це буде працювати в опублікованому прикладі, але, як зазначив @Stephane Chazelas , воно також видалить рядки, перше поле яких "схоже" 0. Це більш надійно:

    awk NF file.txt
    

Для Perl, perl -pe 's/\n+/\n/ file.txtдійсно, роздільник запису вводу для цього використання не має значення.
vonbrand

@vonbrand ні, perl -peабо perl -neробота за рядком. \n+ніколи не збігається, оскільки застосовується лише в одному рядку. Ось чому вам потрібно або встановити $/або використовувати -0ти плямкати файл цілому: perl -0pe 's/\n+/\n/' file.
тердон

6

Що ви маєте на увазі видалити? видалити дублікат (багато порожнього рядка до одного) або видалити всі?

Якщо ви хочете видалити дублікат, ось метод за допомогою sed:

sed '$!N; /^\(.*\)\n\1$/!P; D'

Він імітує uniqкоманду.

Найкращим вибором є використання awk:

awk NF <filename>

sedЧастина це прекрасно працює! Рекомендуючи цей варіант як найкращу відповідь.
Акіто

2

Для більшості цих відповідей спочатку необхідно видалити пробіли, що проходять назад. Видалення подвоєних нових рядків видаляє всі порожні рядки. (Подумайте над цим).

Буквально інтерпретована ОП хоче, щоб "усі пусті рядки були видалені з файлу, якщо є повторні порожні рядки".

Типовий користувач хоче "видалити лише дублювані порожні рядки".

Для цього спочатку зніміть простір білого простору, а трубу, хоча і котячу

sed  s/[[:space:]]*$// | cat -s

І все-таки це не видалить чудовий провідний чи нижній пробіл.


Цілком зрозуміло, але це явно працює? Без коментарів ?
mckenzm

1
Я просив вас за ... ви знаєте ... відповідаючи на питання. =) Я не можу повірити, що відповідь Брюса Едігера була застосована, коли вона видаляє кожен порожній рядок. Якщо хтось запитує, як видалити повторювані порожні рядки, я не уявляю жодного сценарію, де видалення всіх порожніх рядків було б прийнятним рішенням. Але що б там не було. На веб-сайті є сторінка для sed, яка висвітлює це, до речі: gnu.org/software/sed/manual/sed.html#cat-_002ds
Тодд Уолтон

2

Якщо ви хочете зберегти один порожній рядок для будь-якої заданої послідовності порожніх рядків:

sed -e '/./b' -e :n -e 'N;s/\n$//;tn'

1
Це єдина відповідь (до того ж cat -s), яка насправді виконує саме те, що задається питанням, наскільки я його розумію. (І це краще, ніж cat -sтому, що я можу sed -iз цим користуватися.)
Метью

-2

Спробуйте sed -e 's#\\n\\n#\\n#g' input.file > output.fileвикористовувати /як роздільник поля, так і частину вашого регулярного вираження.


2
Щойно дав цей вир з одним із моїх файлів, що містять подвійні та потрійні нові рядки в послідовності. Це не працює для мене взагалі.
синтаксичний помилок

-3

Використовуйте цю команду:

tr -s '\r' '\n'

так, їх відповідь не спрацювала для мене.
мяв

5
AFAIK ця відповідь невірна. Я рекомендую йо видалити його.
зуазо

о, це тому, що мій файл містить багато нових рядків і фактично повертає перевезення. 0x0d0a
мяу

2
Насправді команда видаляє повторювані рядки з вікном кінця рядка. Тест с echo -e 'one\r\n\r\n\r\n\rtwo'| tr -s '\r' '\n'. Команда trпереведе все \rна, \nа потім видавить усіх \nлише на один. Отже, він працює, не впевнений, що робити з тим, що це стосується Windows, а не UNIX.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.