Bagaimana cara grep baris yang memiliki nilai tertentu di kolom tertentu?


9

Saya memiliki file sebagai berikut

  200.000    1.353    0.086
  200.250    1.417    0.000
  200.500    1.359    0.091
  200.750    1.423    0.000
  201.000    1.365    0.093
  201.250    1.427    0.000
  201.500    1.373    0.093
  201.750    1.432    0.000
  202.000    1.383    0.091
  202.250    1.435    0.000
  202.500    1.392    0.087
  202.750    1.436    0.000
  203.000    1.402    0.081
  203.250    1.437    0.001
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

Saya ingin grep hanya baris yang ada di kolom pertama desimal .000 dan .500 saja sehingga hasilnya akan seperti ini

  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

2
Terlihat cukup mudah. Apa yang sudah Anda coba sejauh ini? Masalah apa yang dimiliki kode Anda?
John1024

mungkin itu mudah bagi Anda tetapi saya mencoba dengan grep '.000' | grep '0,005' tetapi juga mengurutkan baris yang memiliki nilai yang sama di kolom lain
Mohsen El-Tahawy

3
Baik sekali. Orang-orang di sini jauh lebih simpatik jika Anda menunjukkan upaya yang jujur ​​untuk menyelesaikan masalah sendiri. Kode dalam komentar Anda menunjukkan hal itu. Di masa depan, jika Anda memasukkan upaya seperti itu dalam pertanyaan Anda, Anda kemungkinan akan mendapatkan respons yang lebih baik lebih cepat.
John1024

Jawaban:


14

Anda tidak menggunakan grep. Gunakan awk.

"your data" | awk '$1 ~ /\.[05]00/'

Baik sekali. Seperti yang tertulis, kode tergantung pada tepat ada tiga digit setelah desimal. Akan lebih kuat untuk digunakan awk '$1 ~ /\.[05]0*$/'.
John1024

1
@ John1024, sebenarnya seperti yang tertulis kode tergantung pada setidaknya ada tiga digit setelah desimal. Saya akan cenderung ke arah awk '$1 ~ /\.[05]00$/', sendiri (memerlukan tepat tiga digit), kecuali saya punya alasan untuk berpikir bahwa tempat desimal variabel diharapkan dalam input.
Wildcard

2
@ Kartu Memori Jika ada lebih dari tiga, kode ini mungkin gagal. Sebagai contoh: echo 0.5001 | awk '$1 ~ /\.[05]00/'. Itu hanya bekerja andal jika ada tepat tiga.
John1024

4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

Kolom pertama $1akan dicocokkan /\.500|\.000/dengan titik-titik yang dilepaskan menjadi titik-titik literal tidak mengubah karakter apa pun yang ~cocok sebagian, dan mencetak seluruh baris$0


2
Tidak ada alasan untuk memasukkan { print $0 }; itu adalah tindakan standar Awk.
Wildcard

4

Saya ingin grep hanya baris yang ada di kolom pertama desimal .000 dan .500

Pikiran pertamaku

grep '^ *[0-9][0-9][0-9]\.[50]00' filename

Tes cepat menggunakan WSL

$ head testdata
              200.000    1.353    0.086
              200.250    1.417    0.000
              200.500    1.359    0.091
              200.750    1.423    0.000
              201.000    1.365    0.093
              201.250    1.427    0.000
              201.500    1.373    0.093
              201.750    1.432    0.000
              202.000    1.383    0.091
              202.250    1.435    0.000
$ grep '^ *[0-9][0-9][0-9]\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Ada cara yang lebih ringkas untuk mengungkapkan ini.

$ grep -E '^ *[0-9]{3}\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Jika kolom pertama mungkin memiliki selain bagian integer 3 digit

grep -E '^ *[0-9]+\.[05]00' testdata

Dalam beberapa situasi Anda mungkin perlu menggunakan [:digit:]di tempat [0-9].

Dan seterusnya.

man grep adalah temanmu


Penggunaan grepini lebih mudah digunakan daripada milik saya. Saya tidak akan memposting jawaban jika saya sudah melihat ini dulu. Pekerjaan yang baik!
Yokai

2

Tergantung pada kasus penggunaan Anda, Anda mungkin juga menggunakan operasi numerik yang sebenarnya:

$ awk '{a = $1 % 1} a == 0 || a == 0.5' /tmp/foo
  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045

Diuji dengan BSD awk (OSX El Capitan, 20070501) dan GNU awk 4.1.4.


1
Peringatan: menguji kesetaraan tepat floating-point (yang menggunakan awk) sering memberikan hasil 'salah' kecuali nilai-nilai tidak memiliki bagian fraksional (dan tidak terlalu besar dalam besarnya), atau bagian fraksional adalah 'biner' (tepat setengah, a seperempat, dll) yang benar untuk data dalam Q ini tetapi tidak banyak orang lain yang tampak mirip dengan yang belum tahu.
dave_thompson_085

1
@ dave_thompson_085 memang, tetapi dengan gawk Anda dapat menggunakan aritmatika presisi sewenang-wenang , memang saya tidak menggunakannya di sini.
muru


2

Dengan awk:

$>awk '$1%.5==0' data.tsv 
200.000 1.353   0.086
200.500 1.359   0.091
201.000 1.365   0.093
201.500 1.373   0.093
202.000 1.383   0.091
202.500 1.392   0.087
203.000 1.402   0.081
203.500 1.412   0.073
204.000 1.423   0.065
204.500 1.432   0.055
205.000 1.441   0.045

Dengan mlr:

$>mlr --ifs tab --onidx filter '$1%.5==0' data.tsv 
200.000 1.353 0.086
200.500 1.359 0.091
201.000 1.365 0.093
201.500 1.373 0.093
202.000 1.383 0.091
202.500 1.392 0.087
203.000 1.402 0.081
203.500 1.412 0.073
204.000 1.423 0.065
204.500 1.432 0.055
205.000 1.441 0.045

2

Ok, sedikit terlambat menambahkan kontribusi saya, tapi saya pikir itu sepadan.

Persyaratan untuk memenuhi, per OP adalah kolom pertama yang memiliki nilai desimal .000atau .500hanya. Tidak ada ketentuan tentang nilai utama, baik dengan rentang atau panjang. Untuk ketahanan, tidak boleh dianggap dibatasi oleh apa pun kecuali bahwa tidak ada karakter yang tidak kosong sebelum kolom pertama (atau bukan lagi kolom pertama) dan bahwa isi kolom pertama akan memiliki titik desimal .,, di suatu tempat.

OP ingin menggunakan grep, yang akan mencetak seluruh baris ketika kecocokan ditemukan, jadi satu-satunya yang harus dilakukan adalah membuat pola yang cocok dengan semua dan hanya apa yang diperlukan.

Kesederhanaan itu sendiri, dan tidak ada alasan untuk menggunakan sedatau awksebagai `grep dapat menangani sumber sebagai file atau pipa.

Untuk grepmenggunakan filegrep '^[^.]*\.[05]0\{2\}\s' the_file.txt

Untuk grepdari pipa, gunakanmy_command | grep '^[^.]*\.[05]0\{2\}\s'

Polanya adalah:, ^mulai dari awal baris; [^.], cocok dengan karakter non-desimal; *, sebanyak mungkin (termasuk tidak ada); \., cocok dengan titik desimal; [05], cocok dengan lima atau nol; 0\{2\}, cocokkan 2 angka nol lagi (backslash sebelum brace buka dan tutup mencegah shell mencoba melakukan ekspansi brace); \s, cocok dengan karakter spasi putih (artinya bagian akhir kolom - untuk digunakan dalam kasus penggunaan yang berbeda, ganti dengan pemisah kolom, biasanya komman, semi-kolon, atau tab \t).

Perhatikan bahwa ini akan cocok persis apa yang OP bertanya. Ini tidak akan cocok .5000atau .0000meskipun setara secara numerik, karena pola mencari lima atau nol, diikuti oleh tepat 2 nol lebih diikuti oleh spasi putih. Jika itu penting, maka semua jawaban lain, sejauh ini, gagal karena mereka akan cocok dengan angka nol, lebih besar dari 1, setelah angka uji. Dan kecuali untuk jawaban oleh FloHimself, mereka akan cocok dengan apa pun di kolom kedua yang dimulai .000 atau .500, termasuk .0003dan .500T, dan yang oleh FloHimself akan cocok dengan apa pun yang secara matematis setara dengan .0dan.5, tidak peduli berapa banyak nol yang ada. Yang terakhir, meskipun tidak cocok dengan apa yang dinyatakan OP kemungkinan cocok dengan apa yang OP butuhkan.

Akhirnya, jika kekuatan, dan kecepatan, awkdiinginkan, meskipun OP meminta grep, maka perintahnya adalah:

Dengan sebuah file awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

Dengan pipa my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'


1

Jika Anda bersikeras menggunakan grep, maka ini mungkin cocok untuk Anda. Saya menyimpan output pertama yang Anda berikan ke file teks bernama, "file.txt" dan kemudian menggunakan perintah berikut:

grep -e '2[^ ]*.000' file.txt & grep -e '2[^ ]*.500' file.txt

Yang menghasilkan output:

200.000    1.353    0.086
200.500    1.359    0.091
201.500    1.373    0.093
201.000    1.365    0.093
202.500    1.392    0.087
202.000    1.383    0.091
203.500    1.412    0.073
203.000    1.402    0.081
204.500    1.432    0.055
204.000    1.423    0.065
205.000    1.441    0.045

Anda tidak perlu menyimpan output ke file teks jika sudah ada dalam file. Tetapi jika itu tidak disimpan ke file, Anda juga dapat menyalurkan data ke perintah grep yang saya berikan dan itu harus bekerja setidaknya sampai angka pertama 2,, di kolom pertama tidak lagi a 2. Pada saat itu Anda perlu memperbarui perintah grep dengan karakter yang sesuai untuk mencetak dengan benar.

Apa yang terjadi dengan grepperintah ganda ini adalah bahwa yang pertama grepdikirim ke latar belakang dengan &operator. Saat dikirim ke latar belakang, grepperintah berikutnya dijalankan segera setelah itu memberi Anda output yang seragam. Untuk tugas yang Anda perlu selesaikan agar dilakukan dengan lebih mudah, Anda harus mengikuti contoh yang telah diberikan dan digunakan orang lain awkatau bahkan sed.

(edit)

Ini bukan berarti penggunaan grep terbaik atau paling efektif untuk kebutuhan Anda, tetapi itu harus cukup memadai bagi Anda untuk bermain-main sedikit dan mendapatkan rasa yang lebih baik untuk grep.


Proses pertama tidak berjalan di latar belakang, tetapi tidak daemonized yang termasuk berjalan di latar tetapi cukup banyak. Dan sangat tidak mungkin untuk menghasilkan output dalam urutan yang sama dengan input; bahkan dalam contoh Anda yang sangat kecil itu sudah salah di baris ketiga.
dave_thompson_085

Dia tidak menyebutkan bahwa output harus dalam urutan tertentu. Hanya itu perlu spesifik untuk .500dan .000dari kolom pertama. Jika perlu dalam urutan tertentu, seperti paling tidak sampai terbesar, itu dapat dengan mudah dilakukan. Namun, 3 digit pertama dari kolom pertama yang dicetak setidaknya dalam urutan terbesar. Itu adalah hasil dari 2[^ ]*.000dan 2[^ ]*.500. Cukup pas dengan apa yang diminta OP.
Yokai

Perhatikan juga edit saya untuk penafian efisiensi untuk perintah yang saya berikan.
Yokai
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.