it-swarm-vi.com

Đếm tổng số lần xuất hiện bằng grep

grep -c rất hữu ích cho việc tìm kiếm bao nhiêu lần một chuỗi xảy ra trong một tệp, nhưng nó chỉ tính mỗi lần xuất hiện một lần trên mỗi dòng. Làm thế nào để đếm nhiều lần xuất hiện trên mỗi dòng?

Tôi đang tìm kiếm một cái gì đó thanh lịch hơn:

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

grep của -o sẽ chỉ xuất các trận đấu, bỏ qua các dòng; wc có thể đếm chúng:

grep -o 'needle' file | wc -l

Điều này cũng sẽ khớp với 'kim' hoặc 'multineedle'.

Để chỉ khớp các từ đơn, sử dụng một trong các lệnh sau:

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

Nếu bạn có GNU grep (luôn có trên Linux và Cygwin, đôi khi ở nơi khác), bạn có thể đếm các dòng đầu ra từ grep -o : grep -o needle | wc -l.

Với Perl, đây là một vài cách tôi thấy thanh lịch hơn của bạn (ngay cả sau khi nó đã sửa ).

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'

Chỉ với các công cụ POSIX, một cách tiếp cận, nếu có thể, là chia đầu vào thành các dòng với một khớp duy nhất trước khi chuyển nó sang grep. Ví dụ: nếu bạn đang tìm kiếm toàn bộ từ, thì trước tiên hãy biến mọi ký tự không phải Word thành một dòng mới.

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

Mặt khác, không có lệnh tiêu chuẩn để thực hiện xử lý văn bản cụ thể này, vì vậy bạn cần chuyển sang sed (nếu bạn là một masochist) hoặc 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

Đây là một giải pháp đơn giản hơn bằng cách sử dụng sedgrep, hoạt động cho các chuỗi hoặc thậm chí các biểu thức thông thường trong sách nhưng không thành công trong một vài trường hợp góc với các mẫu được neo (ví dụ: nó tìm thấy hai lần xuất hiện của ^needle hoặc là \bneedle trong needleneedle).

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

Lưu ý rằng trong các thay thế sed ở trên, tôi đã sử dụng \n có nghĩa là một dòng mới. Đây là tiêu chuẩn trong phần mẫu, nhưng trong văn bản thay thế, về tính di động, thay thế dấu gạch chéo ngược mới cho \n.

Nếu, giống như tôi, bạn thực sự muốn "cả hai; mỗi lần chính xác một lần", (đây thực sự là "một trong hai lần") thì thật đơn giản:

grep -E "thing1|thing2" -c

và kiểm tra đầu ra 2.

Lợi ích của phương pháp này (nếu chính xác một lần những gì bạn muốn) là nó có tỷ lệ dễ dàng.

5
OJFord

Một giải pháp khác sử dụng awk và needle làm dấu tách trường:

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

Nếu bạn muốn khớp needle theo sau là dấu chấm câu, hãy thay đổi dấu tách trường cho phù hợp, tức là.

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

Hoặc sử dụng lớp: [^[:alnum:]] để bao gồm tất cả các ký tự không alpha.

3
ripat

Đây là giải pháp bash tinh khiết của tôi

#!/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

Ví dụ của bạn chỉ in ra số lần xuất hiện trên mỗi dòng chứ không phải tổng số trong tệp. Nếu đó là những gì bạn muốn, một cái gì đó như thế này có thể hoạt động:

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