Hitung jumlah baris kosong di akhir file

11

Saya memiliki file dengan garis kosong di akhir file. Dapatkah saya menggunakan grepuntuk menghitung jumlah baris kosong di akhir file dengan nama file yang diteruskan sebagai variabel dalam skrip?

Raghunath Choudhary
sumber
untuk menghitung jumlah baris kosong berturut - turut ?
RomanPerekhrest
2
@ RomanPerekhrest saya akan berkata begitu, kalau tidak mereka tidak akan "di akhir file"?
Sparhawk
'grep -cv -P' \ S 'nama file' akan menghitung jumlah total baris kosong dalam file. Angka pada akhirnya hanya membebani otak saya!
MichaelJohn
OP meminta grep@MichaelJohn menang untuk kemurnian di buku saya.
bu5hman
2
@ bu5hman Tapi (seperti yang dia akui) tidak menjawab pertanyaan. Kamu juga tidak, sungguh.
Sparhawk

Jawaban:

11

Jika garis kosong hanya di bagian akhir

grep  -c '^$' myFile

atau:

grep -cx '' myFile
bu5hman
sumber
Terkalahkan dengan hasil edit detik, sialan
bu5hman
grep -cv . myFileadalah cara lain untuk menulisnya (untuk pegolf kode). Tapi saya menemukan solusi dengan grepjika ada baris kosong di mana saja dalam file.
Philippos
2
@ Pilipos, grep -cv .juga akan menghitung garis yang hanya berisi byte yang tidak membentuk karakter yang valid.
Stéphane Chazelas
11

Hanya untuk bersenang-senang, beberapa seram sed:

#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l

Penjelasan:

  • /./alamat baris dengan karakter apa pun, jadi /./!alamat baris non-kosong; untuk itu, Hperintah menambahkannya ke ruang tunggu. Jadi, jika untuk setiap baris kosong kami telah menambahkan satu baris ke ruang penahanan, selalu ada satu baris lebih banyak daripada jumlah baris kosong. Kami akan merawatnya nanti.
  • //hpola kosong cocok dengan ekspresi reguler terakhir, yang merupakan karakter apa pun, sehingga setiap baris non-kosong dialamatkan dan dipindahkan ke ruang penahanan oleh hperintah untuk "mengatur ulang" baris yang dikumpulkan ke 1. Ketika baris kosong berikutnya akan ditambahkan, akan ada dua lagi, seperti yang diharapkan.
  • $!dmenghentikan skrip tanpa output untuk setiap kecuali baris terakhir, jadi perintah selanjutnya hanya dijalankan setelah baris terakhir. Jadi, apa pun baris kosong yang kami kumpulkan di ruang penyimpanan ada di akhir file. Baik.
  • //d: dPerintah sekali lagi dieksekusi untuk baris yang tidak kosong. Jadi jika baris terakhir tidak kosong, sedakan keluar tanpa output apa pun. Garis nol. Baik.
  • x pertukaran memegang ruang dan ruang pola, sehingga garis yang dikumpulkan berada dalam ruang pola sekarang untuk diproses.
  • Tetapi kami ingat bahwa ada satu baris terlalu banyak, jadi kami menguranginya dengan menghapus satu baris baru dengan s/\n//.
  • Voa! Jumlah baris cocok dengan jumlah baris kosong di akhir (perhatikan bahwa baris pertama tidak akan kosong, tetapi siapa yang peduli), sehingga kita dapat menghitungnya wc -l.
Filipos
sumber
8

Beberapa GNU tac/ tail -ropsi lain:

tac file | awk 'NF{exit};END{print NR?NR-1:0}'

Atau:

tac file | sed -n '/[^[:blank:]]/q;p' | wc -l

Perhatikan bahwa pada output:

printf 'x\n '

Yaitu, di mana ada ruang tambahan setelah baris penuh terakhir (yang beberapa orang dapat anggap sebagai baris kosong tambahan, tetapi menurut definisi POSIX teks, bukan teks yang valid), mereka akan memberikan 0.

POSIXly:

awk 'NF{n=NR};END{print NR-n}' < file

tetapi itu berarti membaca file secara penuh ( tail -r/ tacakan membaca file mundur dari akhir pada file yang bisa dicari). Itu memberi 1pada output dari printf 'x\n '.

Stéphane Chazelas
sumber
6

Ketika Anda benar-benar meminta grepsolusi, saya menambahkan ini hanya mengandalkan GNU grep(oke, juga menggunakan sintaks shell dan echo...):

#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))

Apa yang saya lakukan disini? $(grep -c ".*" "$1")menghitung semua baris dalam file, lalu kita kurangi file tersebut tanpa mengeklik baris kosong.

Dan bagaimana cara mendapatkannya? $(grep -B42 . "$1"akan menangkap semua baris yang tidak kosong dan 42 baris sebelum mereka, sehingga akan mencetak semuanya hingga baris yang tidak kosong yang terakhir, selama tidak ada lebih dari 42 baris kosong berturut-turut sebelum baris yang tidak kosong. Untuk menghindari batas itu, saya ambil $(grep -cv . "$1")sebagai parameter untuk -Bopsi, yang merupakan jumlah total baris kosong, jadi selalu cukup besar. Dengan cara ini saya telah menghapus garis kosong yang tertinggal dan dapat digunakan |grep -c ".*"untuk menghitung garis.

Cemerlang, bukan? (-;

Filipos
sumber
+1 karena walaupun itu kode yang mengerikan, secara teknis menjawab pertanyaan seperti yang diajukan dan saya tidak tega menandai Anda ;-)
roaima
Grepmeister. Kami tidak layak.
bu5hman
+1 untuk kejahatan. Pilihan lain (mungkin lebih cepat?) Adalah tac | grepke yang pertama kali tidak kosong dengan -m -A 42, kemudian minus satu. Saya tidak yakin mana yang lebih efisien, tetapi Anda juga bisa wc -l | cut -d' ' -f1bukannya mengambil garis kosong?
Sparhawk
Ya, tentu, Anda dapat melakukan banyak hal dengan tac, wcdan cut, tetapi di sini saya mencoba membatasi diri grep. Anda bisa menyebutnya kesesatan, saya menyebutnya olahraga. (-;
Filipi
5

awkSolusi lain . Variasi ini me-reset penghitung ksetiap kali ada garis yang tidak kosong. Lalu, setiap baris menambah penghitung. (Jadi, setelah garis panjang non-kosong pertama k==0.) Pada akhirnya kami menampilkan jumlah garis yang telah kami hitung.

Siapkan file data

cat <<'X' >input.txt
aaa

bbb
ccc



X

Hitung garis kosong yang tertinggal dalam sampel

awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3

Dalam definisi ini, baris kosong mungkin berisi spasi atau karakter kosong lainnya; masih kosong. Jika Anda benar-benar ingin menghitung garis kosong daripada garis kosong, ubah NFuntuk $0 != "".

roaima
sumber
Mengapa $0 > ""? Itu menggunakan strcoll()yang akan kurang efisien daripada $0 != ""yang menggunakan memcmp()dalam banyak implementasi (POSIX digunakan untuk mengharuskannya untuk digunakan strcoll()).
Stéphane Chazelas
@ StéphaneChazelas Saya tidak menganggap itu $0 > ""mungkin berbeda $0 != "". Saya cenderung memperlakukan awksebagai operator "lambat" (sehingga jika saya tahu saya punya dataset besar sebagai input dan prosesnya sangat penting, saya akan melihat apa yang bisa saya lakukan untuk mengurangi jumlah yang awkharus diproses - saya telah menggunakan grep | awkkonstruksi dalam situasi seperti itu). Namun, setelah melihat sekilas apa yang saya asumsikan adalah definisi POSIX saya tidak dapat melihat referensi untuk salah satu strcoll()atau memcmp(). Apa yang saya lewatkan?
roaima
strcoll()== string harus dibandingkan menggunakan urutan pemeriksaan spesifik lokal . Bandingkan dengan edisi sebelumnya . Saya yang membawanya. Lihat juga austingroupbugs.net/view.php?id=963
Stéphane Chazelas
@ StéphaneChazelas implementasi a <= b && a >= byang belum tentu sama dengan a == b. Aduh!
roaima
Itulah kasus GNU awkatau bash(untuk yang [[ a < b ]]operator) di en_US.UTF-8 lokal pada sistem GNU misalnya untuk vs misalnya (untuk bash, tidak ada <, >, =kembali berlaku bagi mereka). Boleh dibilang itu adalah bug dalam definisi lokasi-lokasi itu lebih daripada di bash / awk
Stéphane Chazelas
2

untuk menghitung jumlah baris kosong berturut-turut di akhir file

Solusi padat awk+ tac:

Sampel input.txt:

$ cat input.txt
aaa

bbb
ccc



$  # command line 

Tindakan:

awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
  • !NF- memastikan garis saat ini kosong (tidak memiliki bidang)
  • NR==++c- memastikan urutan baris kosong berturut-turut. ( NR- nomor catatan, ++c- penghitung tambahan yang ditambahkan secara merata)
  • cnt++- Penghitung garis kosong

Hasil:

3
RomanPerekhrest
sumber
1

IIUC, skrip berikut disebut count-blank-at-the-end.shakan melakukan pekerjaan:

#!/usr/bin/env sh

count=$(tail -n +"$(grep . "$1" -n | tail -n 1 | cut -d: -f1)" "$1" | wc -l)
num_of_blank_lines=$((count - 1))

printf "%s\n" "$num_of_blank_lines"

Contoh penggunaan:

$ ./count-blank-at-the-end.sh FILE
4

Saya mengujinya di GNU bash, Android mkshdan di ksh.

Arkadiusz Drabczyk
sumber