grep -c
มีประโยชน์สำหรับการค้นหาจำนวนครั้งที่สตริงเกิดขึ้นในไฟล์ แต่นับเฉพาะแต่ละครั้งที่เกิดขึ้นหนึ่งครั้งต่อบรรทัด จะนับหลายครั้งต่อบรรทัดได้อย่างไร
ฉันกำลังมองหาบางสิ่งที่หรูหรากว่า:
perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'
grep -c
มีประโยชน์สำหรับการค้นหาจำนวนครั้งที่สตริงเกิดขึ้นในไฟล์ แต่นับเฉพาะแต่ละครั้งที่เกิดขึ้นหนึ่งครั้งต่อบรรทัด จะนับหลายครั้งต่อบรรทัดได้อย่างไร
ฉันกำลังมองหาบางสิ่งที่หรูหรากว่า:
perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'
คำตอบ:
grep's -o
จะส่งออกการแข่งขันโดยไม่สนใจเส้น; wc
สามารถนับได้:
grep -o 'needle' file | wc -l
สิ่งนี้จะตรงกับ 'needles' หรือ 'multineedle'
คำเดียวเท่านั้น:
grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
\b
และ\B
ทำที่นี่?
uniq
ลบเฉพาะบรรทัดที่อยู่ติดกันคุณต้องsort
ก่อนที่จะให้อาหารuniq
หากคุณยังไม่แน่ใจว่าซ้ำกันจะอยู่ติดกันทันที
ถ้าคุณมี GNU grep (เสมอบน Linux และ Cygwin บางครั้งอื่น ๆ ) คุณสามารถนับสายออกจากgrep -o
grep -o needle | wc -l
:
ด้วย Perl ต่อไปนี้เป็นวิธีการที่ฉันหาสวยกว่าของคุณมากขึ้น (แม้หลังจากที่แก้ไขแล้ว )
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'
ด้วยเครื่องมือ POSIX เพียงวิธีเดียวถ้าเป็นไปได้คือแยกอินพุตเป็นบรรทัดด้วยการจับคู่เดี่ยวก่อนส่งผ่านไปยัง grep ตัวอย่างเช่นหากคุณกำลังมองหาคำทั้งหมดให้เปลี่ยนอักขระที่ไม่ใช่คำทั้งหมดเป็นบรรทัดใหม่
# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'
มิฉะนั้นไม่มีคำสั่งมาตรฐานที่จะทำการประมวลผลข้อความบิตนี้โดยเฉพาะดังนั้นคุณต้องเปลี่ยนไปใช้ sed (ถ้าคุณเป็นนักทำโทษตนเอง) หรือ 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
ต่อไปนี้เป็นวิธีที่ง่ายกว่าในการใช้sed
และgrep
ซึ่งใช้งานได้กับสตริงหรือนิพจน์ปกติโดยหนังสือ แต่ล้มเหลวในบางมุมที่มีรูปแบบการยึด (เช่นพบว่ามีสองเหตุการณ์เกิดขึ้น^needle
หรือ\bneedle
ในneedleneedle
)
sed 's/needle/\n&\n/g' | grep -cx 'needle'
โปรดทราบว่าในการแทนที่ sed ข้างต้นฉันเคย\n
หมายถึงการขึ้นบรรทัดใหม่ นี่คือมาตรฐานในส่วนของรูปแบบ \n
แต่ในข้อความทดแทนสำหรับการพกพาแทนทับขวาขึ้นบรรทัดใหม่สำหรับ
ถ้าเช่นฉันคุณต้องการ"ทั้งสอง; แต่ละครั้ง", (อันนี้คือ "ทั้งสอง;") แล้วมันง่าย:
grep -E "thing1|thing2" -c
2
และตรวจสอบการส่งออก
ประโยชน์ของวิธีนี้ (ถ้าเพียงครั้งเดียวคือสิ่งที่คุณต้องการ) ก็คือมันปรับขนาดได้อย่างง่ายดาย
โซลูชันอื่นที่ใช้ awk และneedle
ตัวคั่นฟิลด์:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
หากคุณต้องการจับคู่needle
ตามด้วยเครื่องหมายวรรคตอนให้เปลี่ยนตัวคั่นฟิลด์เช่น
awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'
หรือใช้คลาส: [^[:alnum:]]
เพื่อรวมอักขระที่ไม่ใช่อัลฟาทั้งหมด
ตัวอย่างของคุณพิมพ์จำนวนครั้งที่เกิดขึ้นต่อบรรทัดเท่านั้นไม่ใช่จำนวนทั้งหมดในไฟล์ ถ้านั่นคือสิ่งที่คุณต้องการบางอย่างเช่นนี้อาจทำงานได้:
perl -nle '$c+=scalar(()=m/needle/g);END{print $c}'
นี่คือวิธีการทุบตีบริสุทธิ์ของฉัน
#!/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
grep
มีการระบุ แต่สำหรับทุกคนที่ใช้คำตอบก็คือack
ack -ch <pattern>