Hapus baris kosong menggunakan sed

350

Saya mencoba menghapus baris kosong menggunakan sed:

sed '/^$/d'

tapi saya tidak beruntung dengan itu.

Misalnya, saya punya baris berikut:

xxxxxx


yyyyyy


zzzzzz

dan saya ingin menjadi seperti:

xxxxxx
yyyyyy
zzzzzz

Apa yang harus menjadi kode untuk ini?

jonas
sumber
2
perintah sed Anda terlihat baik-baik saja, itu seharusnya berfungsi
perreal
Perintah di atas tidak akan berfungsi bahkan jika Anda tidak memiliki spasi / tab tetapi akhiran garis CR + LF .
devnull

Jawaban:

628

Anda mungkin memiliki spasi atau tab di baris "kosong" Anda. Gunakan kelas POSIX dengan seduntuk menghapus semua baris yang hanya mengandung spasi putih:

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

Versi lebih pendek yang menggunakan ERE, misalnya dengan gnu sed:

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

(Perhatikan bahwa sed TIDAK mendukung PCRE.)

Kent
sumber
3
@HuStmpHrrr gnu sed tidak mendukung PCRE sama sekali. itu adalah ERE dengan-r
Kent
8
sed -i "" '/^[[:space:]]*$/d' <filename>
Dibutuhkan
@BernieReiter ^\s*$akan cocok dengan semua baris "kosong", kosong di sini berarti, baris tidak mengandung karakter, atau baris hanya berisi string kosong (Misalnya spasi). Semua baris yang cocok akan dihapus oleh sed, dengan dperintah.
Kent
96

Saya kehilangan awksolusinya:

awk 'NF' file

Yang akan kembali:

xxxxxx
yyyyyy
zzzzzz

Bagaimana cara kerjanya? Karena NFsingkatan dari "jumlah bidang", baris-baris yang kosong memiliki 0 fiedl, sehingga awk mengevaluasi 0 ke False dan tidak ada garis yang dicetak; Namun, jika ada setidaknya satu bidang, evaluasi adalah Benar dan membuat awkmelakukan tindakan standarnya: cetak baris saat ini.

fedorqui 'SO berhenti merugikan'
sumber
1
Whoah. Bahkan berjalan dengan BSK "meminimalkan" versi awk (versi 20121220 (FreeBSD). Terima kasih :-)
Bernie Reiter
@BernieReiter Anda dipersilakan :) Ya, ini adalah hal idiomatis yang sangat mendasar yang diizinkan oleh semua versi awk.
fedorqui 'SO stop harming'
Dan itu jauh lebih cepat meskipun - untuk tes cepat dan kotor - saya memohon dua kali: $ 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 Apakah Anda tahu cara bagus untuk memasukkan ini ke dalam naskah-awk seperti, misalnya, sebuah pola? awk '/ mypattern / {do stuff ...}'
Bernie Reiter
@BernieReiter bisa Anda katakan awk 'NF {do stuff...}'.
fedorqui 'SO stop harming'
1
Perhatikan bahwa ini juga akan mengabaikan garis dengan spasi saja.
wisbucky
60

sed '/^$/d'harus baik-baik saja, apakah Anda berharap untuk memodifikasi file di tempatnya? Jika demikian, Anda harus menggunakan -ibendera.

Mungkin baris-baris itu tidak kosong, jadi jika itu masalahnya, lihat pertanyaan ini Hapus baris kosong dari txtfiles, hapus spasi dari awal dan akhir baris. Saya yakin itulah yang ingin Anda capai.

Alberto Zaccagni
sumber
Iya. saya memodifikasi file. * .csv. bagaimana seharusnya -i ditempatkan pada perintah sed?
jonas
2
sed -i '/^$/d'adalah salah satu cara untuk melakukannya.
Alberto Zaccagni
49

sed

grep

awk

Oleg Mazko
sumber
1
Ini muncul dengan benar dalam alat online Anda, tapi []harus tidak akan melarikan diri dalam ekspresi braket, sehingga kode di sini adalah tidak benar untuk \[\[:space:\]\]atau \[ \t\]- harus [[:space:]]dan [ \t].
Benjamin W.
1
@BenjaminW. Terima kasih sudah menangkapnya. Itu bukan dari penulis asli, tetapi berasal dari Edit 3 ketika itu diubah dari teks biasa menjadi "kode", yang kemudian "mengekspos" yang melarikan diri. Saya sudah memperbaikinya sekarang.
wisbucky
30

Saya percaya ini yang termudah dan tercepat:

cat file.txt | grep .

Jika Anda perlu mengabaikan semua garis ruang putih juga maka coba ini:

cat file.txt | grep '\S'

Contoh:

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

output

7
5
Vadim
sumber
5
Tidak perlu cat, grepbawa file juga:grep . file.txt
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
3
Ya, saya tahu, tetapi pertanyaan awal tidak menyebutkan apakah sumbernya adalah file atau yang lain, jadi solusinya adalah apa yang muncul setelah "|", dan sebelum itu hanya sebuah contoh sumber. Cukup untuk membedakan solusi dari sumber garis.
Vadim
2
grep '\S'jelas tidak portabel. Jika sudah, grep -PAnda dapat menggunakannya grep -P '\S'tetapi tidak didukung di semua platform.
tripleee
Kelemahan dari grep .dibandingkan dengan solusi lain adalah akan menyoroti semua teks berwarna merah. Solusi lain dapat mempertahankan warna asli. Bandingkan unbuffer apt search foo | grep .denganunbuffer apt search foo | grep -v ^$
wisbucky
15

Dengan bantuan dari jawaban yang diterima di sini dan jawaban yang diterima di atas, saya telah menggunakan:

$ 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

Ini mencakup semua pangkalan dan berfungsi dengan baik untuk kebutuhan saya. Kudos ke poster asli @Kent dan @kev

Penipu
sumber
5

Anda bisa mengatakan:

sed -n '/ / p' filename    #there is a space between '//'
tangki
sumber
.. Yang berarti print all lines except the empty one(s)dan diam
Timo
2

Anda dapat melakukan hal seperti itu menggunakan "grep" juga:

egrep -v "^$" file.txt
Lowbit
sumber
2

Ini bekerja dengan awk juga.

awk '!/^$/' file
xxxxxx
yyyyyy
zzzzzz
Claes Wikner
sumber
2

Anda kemungkinan besar melihat perilaku yang tidak terduga karena file teks Anda dibuat pada Windows, jadi urutan akhir barisnya adalah \r\n. Anda dapat menggunakan dos2unix untuk mengonversinya menjadi file teks gaya UNIX sebelum menjalankan atau menggunakan

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

untuk menghapus garis kosong apakah carriage return ada atau tidak.

FauChristian
sumber
Hai, apa yang -rdilakukan flag dan apakah mungkin untuk menggabungkannya dengan -imemodifikasi file secara langsung dan menghindari pencetakan ke layar. Selain itu, saya berpikir bahwa perintah ini juga akan berfungsi sebagaised -r "/^\r$/d"
Alexander Cska
2

Pilihan lain tanpa sed, awk, perl, dll

strings $file > $output

string - mencetak string karakter yang dapat dicetak dalam file.

pengguna319660
sumber
Apakah maksud Anda stringsalih-alih string?
Mickael B.
Hai @MickaelB. Anda benar, saya memperbaikinya.
user319660
0

bashJawaban khusus saya adalah merekomendasikan menggunakan perloperator substitusi dengan tanda pola global guntuk ini, sebagai berikut:

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

Jawaban ini menggambarkan akuntansi untuk apakah baris kosong memiliki spasi di dalamnya ( [\ ]*), serta digunakan |untuk memisahkan beberapa istilah / bidang pencarian. Diuji pada macOS High Sierra dan CentOS 6/7.

FYI, kode asli OP sed '/^$/d' $fileberfungsi dengan baik di bashTerminal pada macOS High Sierra dan CentOS 6/7 Linux di cluster superkomputer berkinerja tinggi.

justincbagley
sumber
-3

Bagi saya dengan FreeBSD 10.1 dengan sed hanya bekerja solusi ini:

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

di dalamnya []ada simbol spasi dan tab.

file tes berisi:

fffffff next 1 tabline ffffffffffff

ffffffff next 1 Space line ffffffffffff

ffffffff empty 1 lines ffffffffffff

============ EOF =============
Vitaly
sumber