it-swarm-id.com

Hitung jumlah total kejadian menggunakan grep

grep -c berguna untuk menemukan berapa kali string muncul dalam file, tetapi itu hanya menghitung setiap kemunculan sekali per baris. Bagaimana cara menghitung beberapa kejadian per baris?

Saya mencari sesuatu yang lebih elegan daripada:

Perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'
242
user4518

grep's -o hanya akan menghasilkan pertandingan, mengabaikan garis; wc dapat menghitungnya:

grep -o 'needle' file | wc -l

Ini juga akan cocok dengan 'jarum' atau 'multineedle'.

Untuk mencocokkan hanya satu kata, gunakan salah satu dari perintah berikut:

grep -ow 'needle' file | wc -l
grep -o '\bneedle\b' file | wc -l
grep -o '\<needle\>' file | wc -l
352
wag

Jika Anda memiliki GNU grep (selalu di Linux dan Cygwin, kadang-kadang di tempat lain), Anda bisa hitung garis output dari grep -o : grep -o needle | wc -l.

Dengan Perl, berikut adalah beberapa cara yang saya anggap lebih elegan dari milik Anda (bahkan setelah itu diperbaiki ).

Perl -lne 'END {print $c} map ++$c, /needle/g'
Perl -lne 'END {print $c} $c += s/needle//g'
Perl -lne 'END {print $c} ++$c while /needle/g'

Dengan hanya alat POSIX, satu pendekatan, jika mungkin, adalah membagi input menjadi garis dengan satu kecocokan sebelum meneruskannya ke grep. Misalnya, jika Anda mencari seluruh kata, maka pertama-tama ubah setiap karakter non-Word menjadi baris baru.

# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'

Kalau tidak, tidak ada perintah standar untuk melakukan sedikit pemrosesan teks ini, jadi Anda perlu beralih ke sed (jika Anda seorang masokis) atau awk.

awk '{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}}
     END {print c}'
sed -n -e 's/set/\n&\n/g' -e 's/^/\n/' -e 's/$/\n/' \
       -e 's/\n[^\n]*\n/\n/g' -e 's/^\n//' -e 's/\n$//' \
       -e '/./p' | wc -l

Berikut adalah solusi sederhana menggunakan sed dan grep, yang berfungsi untuk string atau bahkan oleh-the-book regular expressions tetapi gagal dalam beberapa kasus sudut dengan pola berlabuh (misalnya menemukan dua kemunculan ^needle atau \bneedle dalam needleneedle).

sed 's/needle/\n&\n/g' | grep -cx 'needle'

Perhatikan bahwa dalam substitusi sed di atas, saya menggunakan \n berarti baris baru. Ini adalah standar di bagian pola, tetapi dalam teks pengganti, untuk portabilitas, gantikan backslash-newline untuk \n.

Jika, seperti saya, Anda benar-benar menginginkannya "keduanya; masing-masing tepat sekali", (ini sebenarnya "baik; dua kali") maka itu sederhana:

grep -E "thing1|thing2" -c

dan periksa hasilnya 2.

Manfaat dari pendekatan ini (jika tepat satu kali adalah apa yang Anda inginkan) adalah ia berskala dengan mudah.

5
OJFord

Solusi lain menggunakan awk dan needle sebagai pemisah bidang:

awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'

Jika Anda ingin mencocokkan needle diikuti dengan tanda baca, ubah pemisah bidang sesuai dengan mis.

awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'

Atau gunakan kelas: [^[:alnum:]] untuk mencakup semua karakter non alpha.

3
ripat

Ini adalah solusi bash murni saya

#!/bin/bash

B=$(for i in $(cat /tmp/a | sort -u); do
echo "$(grep $i /tmp/a | wc -l) $i"
done)

echo "$B" | sort --reverse
1
Felipe

Contoh Anda hanya mencetak jumlah kemunculan per-baris, dan bukan total dalam file. Jika itu yang Anda inginkan, sesuatu seperti ini mungkin berhasil:

Perl -nle '$c+=scalar(()=m/needle/g);END{print $c}' 
1
jsbillings