Grep menghapus baris dengan 0 tetapi tidak 0,2?


12

Saya memiliki file yang isinya mirip dengan yang berikut.

0
0
0.2
0
0
0
0

Saya perlu menghapus semua baris dengan nol tunggal.
Saya berpikir untuk menggunakan grep -v "0", tetapi ini juga menghapus baris yang berisi 0,2. Saya melihat saya bisa menggunakan -wopsi ini, tetapi sepertinya ini juga tidak berhasil.

Bagaimana saya bisa menghapus semua baris yang hanya mengandung satu 0 dan menjaga semua baris itu dimulai dengan 0?



1
@JulienLopez Ini bukan penipuan dari pertanyaan itu. Pertanyaan itu adalah tentang mencocokkan sebuah kata, dan menjawab dengan -w, yang gagal di sini.
Sparhawk

Mengapa Anda terpaksa menggunakan grepuntuk tugas ini? Dan apa sebenarnya yang Anda maksud dengan satu nol ? Ini terdengar seperti masalah XY .
Roland Illig

1
@RolandIllig itu 1 jam sebelum tidur dan saya ingin mulai memproses serangkaian 500.000 string untuk memeriksa apakah itu adalah kunci pribadi bitcoin dan jika demikian dapatkan keseimbangan. Lain kali saya punya waktu untuk melihatnya saya telah memproses ribuan string dan saya hanya ingin menguraikan nilai-nilai yang tidak nol.
Philip Kirkbride

Jawaban:


35
grep -vx 0

Dari man grep:

-x, --line-regexp
       Select only those matches that exactly match the whole line.
       For a regular expression pattern, this is like parenthesizing
       the pattern and then surrounding it with ^ and $.

-wgagal karena 0in pertama 0.02dianggap sebagai "kata", dan karenanya baris ini cocok. Ini karena diikuti oleh karakter "non-kata". Anda dapat melihat ini jika Anda menjalankan perintah asli tanpa -v, yaitu grep -w "0".


Anda juga dapat menggunakan -Fopsi karena kita tidak menggunakan pola regex, hanya pencocokan string biasa
glenn jackman

@glennjackman Mungkin saya sudah membaca ini sebelumnya, tetapi saya tidak bisa menemukannya sekarang. Menjalankan dengan -F(mengejutkan bagi saya) tampaknya membutuhkan jumlah waktu yang sama atau bahkan sedikit lebih lambat (~ 5-10%). Karenanya, saya tidak yakin apa keuntungannya.
Sparhawk

2
Mungkin saja mesin RegEx sering digunakan dan digunakan secara luas sehingga mereka telah mengimplementasikan versi yang sangat efisien, tetapi "pencarian biasa" mungkin belum ditingkatkan selama 30 tahun.
Nelson

@Sparhawk: grepmungkin memiliki case khusus untuk regex tanpa metacharacters, karena itu adalah case-use yang umum. Ini mengejutkan bahwa fgrepakan lebih lambat, tetapi tidak mengherankan bahwa overhead memperhatikan kasus khusus ini ketika menyusun pola pendek dapat diabaikan dibandingkan waktu untuk memindai file besar. (Jika memerlukan kasus khusus sama sekali untuk pergi secepat itu, vs. pola dengan kelas karakter atau x.*y.)
Peter Cordes

Tapi itu mungkin penyederhanaan yang berlebihan karena inputnya sebenarnya banyak garis pendek (bukan satu string raksasa). Saya lupa jika grepmengenali karakter selain \nbaris baru sebagai pemisah baris. Jika tidak, implisit ^dan $ masih bisa berubah menjadi seperti pencarian string tetap strstr(big_buf, "\n0\n"). (Atau 0\ndi awal buffer.) Tapi kami tidak hanya mencari pertandingan pertama yang berpotensi jauh menjadi buffer besar, kami ingin memfilter secara efisien. Tapi bagaimanapun, secara teori ya itu hanya memcmp 2-byte pada awal setiap baris, dan Anda akan berharap bahwa baik fgrep dan grep akan melihatnya.
Peter Cordes

28

Dengan grep:

grep -v "^0$" file

^berarti awal baris, $berarti akhir baris.


2
Inilah yang diminta pengguna: hindari setiap baris yang hanya mengandung 1 "0".
Olivier Dulac

1
Saya tidak akan memasukkan tanda dolar literal ke dalam tanda kutip ganda seperti itu.
user541686

@mehrdad bukan masalah besar dengan regex seperti biasanya char terakhir atau berikutnya tidak akan[a-Z0-9]
Sampo Sarrala - codidact.org

14

Meskipun grep dapat digunakan untuk ini (seperti yang ditunjukkan oleh jawaban lain dengan jelas), mari selangkah mundur dan pikirkan apa yang sebenarnya Anda inginkan:

  • Anda memiliki file yang berisi angka
  • Anda ingin melakukan pemfilteran berdasarkan nilai numerik .

Regex menginterpretasikan data urutan karakter. Mereka tidak tahu tentang angka, hanya tentang digit individu (dan kombinasi regulernya). Meskipun dalam kasus khusus Anda ada peretasan sederhana di sekitar batasan ini, itu pada akhirnya merupakan ketidakcocokan persyaratan.

Kecuali ada alasan yang sangat bagus untuk digunakan di grepsini (misalnya karena Anda telah mengukurnya, dan jauh lebih efisien, dan efisiensi sangat penting dalam kasus Anda), saya sarankan menggunakan alat yang berbeda.

awk, misalnya, dapat memfilter berdasarkan perbandingan numerik, misalnya:

awk '$1 == 0' your_file

Tetapi juga, untuk mendapatkan semua baris yang berisi angka lebih besar dari nol:

awk '$1 > 0' your_file

Saya suka regex, ini alat yang hebat. Tapi itu bukan satu - satunya alat. Seperti kata pepatah, jika semua yang Anda miliki adalah grep, semuanya tampak seperti bahasa biasa.


3
Saya sepenuh hati setuju bahwa awk mungkin lebih elegan di sini ... namun, itu juga akan cocok mungkin sedikit lebih dari apa yang diharapkan pengguna (setiap nilai numerik bernilai 0). Yaitu, printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'akan cocok: 0, 0.0dan -0.0... dan juga 0 also! Bukan hanya "0". (yang terkadang dibutuhkan, kadang tidak). Jika pengguna hanya menginginkan "0": awk '/^0$/' (atau grep '^0$'). Anda juga harus mengedit: pengguna perlu menambahkan !untuk meniadakan tes, sehingga menyembunyikan 0(dan nol lainnya) dan menampilkan sisanya. yaitu:awk '!( $0 == 0)'
Olivier Dulac

1
@ Olivier, atau periksa nilai string:$1 == "0"
glenn jackman

1
@OlivierDulac I secara eksplisit digunakan >daripada !=(atau, setara, ! (… == …)) untuk menyoroti bahwa ini adalah perbandingan numerik sewenang-wenang, bukan hanya kesetaraan. Adapun komentar Anda yang lain, ini sepenuhnya benar tetapi kemudian kami pada dasarnya kembali dalam wilayah perbandingan string dan solusi yang ada menggunakan grepkarya (meskipun awktentu saja juga berfungsi).
Konrad Rudolph

@KonradRudolph poin adil :)
Olivier Dulac

1
@glennjackman: memang trik yang bagus. Tapi kemudian OP lebih suka melakukan tes$0=="0"
Olivier Dulac

5

grep's -wadalah sedikit berbelit-belit dengan cara yang terpecah string asli ke kata dan non-kata konstituen (apa-apa kecuali huruf, angka atau garis bawah). Karena telah menemukan konstituen kata yang valid 0di 0.02dalamnya telah menegaskan logika negasi untuk menghapus baris.

Menggunakannya sedagak mudah dalam konteks ini untuk hanya menghapus seluruh kata yang cocok

sed '/^0$/d' file

3

Ketika garis-garis yang ingin dihapus hanya mengandung sebuah 0 diikuti oleh baris berikutnya Anda dapat memilih garis dengan mengeluarkan perintah berikut:

grep -v "^0$"

Ini hanya akan mencetak kemunculan 0yang ada di akhir baris dan di awal baris pada saat bersamaan. The -vpilihan kemudian membalikkan pilihan.


1
Jawaban ini hampir identik dengan Arkadiusz Drabczyk, tetapi Anda lupa -v, jadi itu tidak berhasil.
Sparhawk

Kamu benar. Saya mengetik sementara dia memposting jawabannya jadi saya tidak melihat itu sudah diberikan. Saya salah membaca bagian itu dengan -vopsi, terima kasih!
majesticLSD

0
  • \ b - batas kata

grep -v "\b0\b"

  • cocok dengan awal garis, pola Anda dan ujung garis

grep -v "^0$"

  • atau seperti yang disarankan @Sparhawk -vx lineregexp

-w berfungsi, tetapi dalam kasus Anda 0.2 adalah dua kata karena karakter titik adalah pemisah kata.


grep -v "\b0\b"tidak benar-benar bekerja di sini. Versi grep apa yang Anda gunakan?
Arkadiusz Drabczyk

bekerja dengan grep (BSD grep) 2.5.1-FreeBSDdi macOS dan grep (GNU grep) 2.16di ubuntu
Jakub Jindra

1
Penggunaan regex GNU \<dan \>sebagai batas kata, tetapi itu akan memiliki efek yang sama dengan-w
glenn jackman

0

Jawaban lain demi variasi, dengan asumsi Anda memiliki PCRE-enabled grep

grep -Pv "^0(?!\.)"

ini melakukan lookahead negatif untuk mencocokkan garis yang dimulai dengan 0dan tidak diikuti oleh titik. Kemudian -vbuang garis yang tidak cocok. Anda dapat melihat beraksi di sini


1
Ini juga akan menghapus garis-garis seperti 0123, yang bukan itu yang diinginkan OP
iruvar

0

Dengan asumsi setiap baris yang bukan hanya satu 0 memiliki titik

grep '\.' file

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.