Удалите пустые строки, используя 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.