Usuń puste linie za pomocą sed


349

Próbuję usunąć puste linie za pomocą sed:

sed '/^$/d'

ale nie mam z tym szczęścia.

Na przykład mam następujące linie:

xxxxxx


yyyyyy


zzzzzz

i chcę, żeby wyglądało to tak:

xxxxxx
yyyyyy
zzzzzz

Jaki powinien być kod tego?


2
twoje polecenie sed wygląda dobrze, powinno działać
perreal

Powyższe polecenie nie działałoby, nawet jeśli nie masz spacji / tabulacji, ale zakończenia linii CR + LF .
devnull

Odpowiedzi:


626

W swoim „pustym” wierszu mogą znajdować się spacje lub tabulatory. Użyj klas POSIX z, sedaby usunąć wszystkie wiersze zawierające tylko białe znaki:

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

Krótsza wersja korzystająca z ERE, na przykład z gnu sed:

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

(Zauważ, że sed NIE obsługuje PCRE.)


3
@HuStmpHrrr gnu sed w ogóle nie obsługuje PCRE. jest ERE z-r
Kent

8
Potrzebny jest OS X sed -i "" '/^[[:space:]]*$/d' <filename>,
jww

@BernieReiter ^\s*$dopasuje wszystkie „puste” linie, puste tutaj oznacza, linia nie zawiera znaków, lub linia zawiera tylko puste ciągi (np. Spacje). Wszystkie dopasowane linie zostaną usunięte za pomocą dpolecenia sed .
Kent

96

Brakuje mi awkrozwiązania:

awk 'NF' file

Które zwróci:

xxxxxx
yyyyyy
zzzzzz

Jak to działa? Ponieważ NFoznacza „liczbę pól”, puste linie mają 0 fiedlów, dzięki czemu awk ocenia 0 na False i żaden wiersz nie jest drukowany; jednak jeśli jest co najmniej jedno pole, ocena ma wartość Prawda i powoduje awkwykonanie domyślnej akcji: wydrukuj bieżącą linię.


1
Whoah Działa nawet z „zminimalizowaną” wersją awk BSD (wersja 20121220 (FreeBSD). Dzięki :-)
Bernie Reiter

@BernieReiter jesteś mile widziany :) Tak, jest to bardzo prosta idiomatyczna rzecz, na którą pozwalają wszystkie wersje awk.
fedorqui „SO przestań krzywdzić”

I to jest o wiele szybsze, chociaż - dla szybkiego i brudnego testu - wzywam awk dwa razy: $ 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 Czy znasz dobry sposób na włączenie tego do skryptu awk, np. Wzorca? awk '/ mypattern / {do stuff ...}'
Bernie Reiter

@BernieReiter możesz powiedzieć awk 'NF {do stuff...}'.
fedorqui „SO przestań szkodzić”

1
Zauważ, że spowoduje to również zignorowanie linii z białymi spacjami.
wisbucky,

60

sed '/^$/d'powinno być w porządku, czy spodziewasz się zmodyfikować plik na miejscu? Jeśli tak, powinieneś użyć -iflagi.

Może te linie nie są puste, więc jeśli tak jest, spójrz na to pytanie Usuń puste linie z plików txt, usuń spacje od początku i końca linii Wierzę, że to właśnie próbujesz osiągnąć.


tak. modyfikuję plik. * .csv. jak należy umieścić -i w poleceniu sed?
jonas

2
sed -i '/^$/d'jest jednym ze sposobów na zrobienie tego.
Alberto Zaccagni

49

1
Są one poprawnie wyświetlane w narzędziu online, ale nie[] należy ich umieszczać w nawiasach, więc tutaj kod nie jest poprawny dla - \[\[:space:\]\]lub \[ \t\]powinien być [[:space:]]i [ \t].
Benjamin W.,

1
@BenjaminW. Dzięki za złapanie tego. Nie pochodziły one od oryginalnego autora, ale pochodziły z Edit 3, kiedy zmieniono go ze zwykłego tekstu na „kod”, który następnie „odsłonił” ucieczkę `\ '. Naprawiłem je teraz.
wisbucky,

30

Uważam, że jest to najłatwiejszy i najszybszy:

cat file.txt | grep .

Jeśli chcesz zignorować również wszystkie białe znaki, spróbuj tego:

cat file.txt | grep '\S'

Przykład:

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

wyjścia

7
5

5
Nie ma potrzeby cat, greppobiera również pliki:grep . file.txt
Ciro Santilli 16 冠状 病 六四 事件 法轮功

3
Tak, wiem, ale początkowe pytanie nie wspomniało, czy źródłem jest plik, czy coś innego, więc rozwiązaniem jest to, co następuje po „|”, a przed nim tylko przykład źródła. Wystarczy odróżnić rozwiązanie od źródła linii.
Vadim

2
grep '\S'zdecydowanie nie jest przenośny. Jeśli masz grep -P, możesz użyć, grep -P '\S'ale nie jest obsługiwany na wszystkich platformach.
tripleee

Minusem w grep .porównaniu z innymi rozwiązaniami jest to, że podświetli cały tekst na czerwono. Inne rozwiązania mogą zachować oryginalne kolory. Porównaj unbuffer apt search foo | grep .zunbuffer apt search foo | grep -v ^$
wisbucky,

15

Z pomocą tutaj zaakceptowanej odpowiedzi i powyższej odpowiedzi wykorzystałem:

$ 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

Obejmuje wszystkie podstawy i działa idealnie dla moich potrzeb. Uznanie dla oryginalnych plakatów @Kent i @kev


5

Możesz powiedzieć:

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

.. co oznacza print all lines except the empty one(s)i bądź cicho
Timo

2

Możesz zrobić coś takiego za pomocą „grep”:

egrep -v "^$" file.txt


2

Najprawdopodobniej widzisz nieoczekiwane zachowanie, ponieważ plik tekstowy został utworzony w systemie Windows, więc sekwencja końca linii to \r\n. Możesz użyć dos2unix, aby przekonwertować go do pliku tekstowego w stylu UNIX przed uruchomieniem sed lub użyj

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

aby usunąć puste linie bez względu na to, czy jest tam znak powrotu karetki.


Cześć, co -rrobi flaga i czy można ją połączyć, -iaby bezpośrednio zmodyfikować plik i uniknąć drukowania na ekranie. Ponadto myślę, że to polecenie również działałoby jakosed -r "/^\r$/d"
Alexander Cska,

2

Inną opcją bez sed, awk, perl, etc

strings $file > $output

strings - drukuje ciągi znaków do wydrukowania w plikach.


Masz na myśli stringszamiast string?
Mickael B.

Cześć @MickaelB. Masz rację, naprawiam to.
user319660

0

Moją bashspecyficzną odpowiedzią jest zalecenie użycia w tym celu perloperatora podstawienia z globalną gflagą wzorca :

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

Ta odpowiedź ilustruje rozliczenie, czy puste linie mają spacje ( [\ ]*), a także użycie| do oddzielenia wielu wyszukiwanych terminów / pól. Testowane na macOS High Sierra i CentOS 6/7.

FYI, oryginalny kod OP sed '/^$/d' $filedziała dobrze w bashTerminalu na macOS High Sierra i CentOS 6/7 Linux w wysoko wydajnym klastrze superkomputerowym.


-3

Dla mnie z FreeBSD 10.1 z sed pracował tylko to rozwiązanie:

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

wewnątrz []są spacje i symbole tabulatorów.

plik testowy zawiera:

fffffff next 1 tabline ffffffffffff

ffffffff next 1 Space line ffffffffffff

ffffffff empty 1 lines ffffffffffff

============ EOF =============
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.