Удалите пустые строки, используя sed


351

Я пытаюсь удалить пустые строки с помощью sed:

sed '/^$/d'

но мне не повезло с этим.

Например, у меня есть эти строки:

xxxxxx


yyyyyy


zzzzzz

и я хочу, чтобы это было так:

xxxxxx
yyyyyy
zzzzzz

Каким должен быть код для этого?


2
ваша команда sed выглядит нормально, она должна работать
— perreal

Вышеприведенная команда не сработает, даже если у вас нет пробела / табуляции, но есть окончания строк CR + LF .
— Devnull

Ответы:


628

В вашей «пустой» строке могут быть пробелы или символы табуляции. Используйте классы POSIX с, sedчтобы удалить все строки, содержащие только пробелы:

sed '/^[[:space:]]*$/d'

Более короткая версия, которая использует ERE, например, с gnu sed:

sed -r '/^\s*$/d'

(Обратите внимание, что sed НЕ поддерживает PCRE.)


3
@HuStmpHrrr gnu sed вообще не поддерживает PCRE. это ERE с-r
— Кент

8
OS X требуется sed -i "" '/^[[:space:]]*$/d' <filename>,
— jww

@BernieReiter ^\s*$будет соответствовать всем «пустым» строкам, здесь означает «пустое», строка не содержит символов или строка содержит только пустые строки (например, пробелы). Все совпавшие строки будут удалены командой sed d.
— Кент

97

Мне не хватает awkрешения:

awk 'NF' file

Который вернется:

xxxxxx
yyyyyy
zzzzzz

Как это работает? Так как NFобозначает «количество полей», эти строки, которые являются пустыми, имеют 0 строк, так что awk оценивает 0 как False и строка не печатается; однако, если есть хотя бы одно поле, оценка имеет значение True и awkвыполняет свое действие по умолчанию: вывести текущую строку.


1
Whoah. Даже работает с "свернутой" версией BSD awk (версия 20121220 (FreeBSD). Спасибо :-)
— Берни Рейтер

@ BernieReiter, добро пожаловать :) Да, это очень простая идиоматическая вещь, которую позволяют все версии awk.
— Федорки "ТАК прекрати вредить"

И это намного быстрее, хотя - для быстрого и грязного теста - я дважды вызываю awk: $ time (topic companies <data.tpx | awk 'NF' - | awk -f dialog_menu.awk -) real 0m0.006s user 0m0.000s sys 0m0.008s $ time (topic companies <data.tpx | gsed '/^\s*$/d' | awk -f dialog_menu.awk -) real 0m0.014s user 0m0.002s sys 0m0.006s знаете ли вы изящный способ включить это в сценарий awk, например, в шаблон? awk '/ mypattern / {do stuff ...}'
— Берни Рейтер

@BernieReiter вы можете сказать awk 'NF {do stuff...}'.
— Федорки "ТАК прекрати вредить"

1
Обратите внимание, что при этом также будут игнорироваться строки только с пробелами.
— wisbucky

60

sed '/^$/d'должно быть хорошо, вы ожидаете изменить файл на месте? Если это так, вы должны использовать-i флаг.

Возможно, эти строки не пусты, поэтому, если это так, посмотрите на этот вопрос. Удалите пустые строки из txtfiles, удалите пробелы в начале и конце строки. Я считаю, что это то, чего вы пытаетесь достичь.


да. Я изменяю файл. * .csv. как поместить -i в команду sed?
— Джонас

2
sed -i '/^$/d'это один из способов сделать это.
— Альберто Закканьи

49

1
Они показывают правильно в вашем интернет - инструмент, но []должен не быть экранированы в выражении скобки, поэтому здесь код не является правильным для\[\[:space:\]\] или \[ \t\]- должно быть [[:space:]]и [ \t].
— Бенджамин В.

1
@BenjaminW. Спасибо, что поймали это. Они не были от оригинального автора, но пришли из Edit 3, когда он был изменен с обычного текста на «код», который затем «выставил» экранирование «\». Я исправил их сейчас.
— wisbucky

30

Я считаю, что это самый простой и быстрый:

cat file.txt | grep .

Если вам нужно также игнорировать все пробелы, попробуйте следующее:

cat file.txt | grep '\S'

Пример:

s="\
\
a\
 b\
\
Below is TAB:\
    \
Below is space:\
 \
c\
\
"; echo "$s" | grep . | wc -l; echo "$s" | grep '\S' | wc -l

выходы

7
5

5
Не нужно cat, также grepпринимает файлы:grep . file.txt
— Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

3
Да, я знаю, но в первоначальном вопросе не упоминалось, является ли источник файлом или чем-то еще, поэтому решение - это то, что следует после «|», а перед ним просто пример источника. Просто чтобы отличить решение от источника линий.
— Вадим

2
grep '\S'определенно не портативен. Если у вас есть, grep -Pто вы можете использовать, grep -P '\S'но это поддерживается не на всех платформах.
— tripleee

Недостатком по grep .сравнению с другими решениями является то, что он выделит весь текст красным цветом. Другие решения могут сохранить оригинальные цвета. Сравните unbuffer apt search foo | grep .сunbuffer apt search foo | grep -v ^$
— wisbucky

15

С помощью принятого ответа здесь и принятого ответа выше, я использовал:

$ sed 's/^ *//; s/ *$//; /^$/d; /^\s*$/d' file.txt > output.txt

`s/^ *//`  => left trim
`s/ *$//`  => right trim
`/^$/d`    => remove empty line
`/^\s*$/d` => delete lines which may contain white space

Это охватывает все основы и отлично работает для моих нужд. Слава оригинальным постерам @Kent и @kev


5

Ты можешь сказать:

sed -n '/ / p' filename    #there is a space between '//'

.. что значит print all lines except the empty one(s)и молчи
— Тимо

3

Другой вариант без sed, awk, perlи т.д.

strings $file > $output

strings - печатать строки печатаемых символов в файлах.


Вы имеете в виду stringsвместо string?
— Микаэль Б.

2

Вы можете сделать что-то подобное, используя "grep":

egrep -v "^$" file.txt


2

Скорее всего, вы видите неожиданное поведение, потому что ваш текстовый файл был создан в Windows, поэтому конец строки строки \r\n. Вы можете использовать dos2unix, чтобы преобразовать его в текстовый файл в стиле UNIX перед тем, как запускать sed или использовать

sed -r "/^\r?$/d"

удалить пустые строки независимо от того, есть ли возврат каретки.


Привет, что -rделает флаг, и можно ли его объединить, -iчтобы напрямую изменить файл и избежать печати на экране. Кроме того, я думаю, что эта команда также будет работать какsed -r "/^\r$/d"
— Александр Cska

0

Мой bashспецифический ответ - рекомендовать для этого использовать perlоператор подстановки с глобальным gфлагом шаблона :

$ perl -pe s'/^\n|^[\ ]*\n//g' $file
xxxxxx
yyyyyy
zzzzzz

Этот ответ иллюстрирует учет наличия или отсутствия пустых строк в них ( [\ ]*), а также использование |для разделения нескольких поисковых терминов / полей. Протестировано на macOS High Sierra и CentOS 6/7.

Кстати, оригинальный код OP прекрасно sed '/^$/d' $fileработает в bashтерминале на macOS High Sierra и CentOS 6/7 Linux на высокопроизводительном суперкомпьютерном кластере.


-3

У меня с FreeBSD 10.1 с sed работало только это решение:

sed -e '/^[     ]*$/d' "testfile"

внутри [] есть символы пробела и табуляции.

Тестовый файл содержит:

fffffff next 1 tabline ffffffffffff

ffffffff next 1 Space line ffffffffffff

ffffffff empty 1 lines ffffffffffff

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