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

СЭД

Grep

AWK

Олег Мазько
источник
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 - печатать строки печатаемых символов в файлах.

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

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

egrep -v "^$" file.txt
Lowbit
источник
2

Это работает и в awk.

awk '!/^$/' file
xxxxxx
yyyyyy
zzzzzz
Клас Викнер
источник
2

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

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

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

FauChristian
источник
Привет, что -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 на высокопроизводительном суперкомпьютерном кластере.

justincbagley
источник
-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 =============
Виталий
источник