ฉันจะนับจำนวนครั้งของคำในไฟล์ข้อความด้วยบรรทัดคำสั่งได้อย่างไร


43

ฉันมีไฟล์ JSON ขนาดใหญ่ที่อยู่บนบรรทัดเดียวและฉันต้องการใช้บรรทัดคำสั่งเพื่อให้สามารถนับจำนวนคำที่เกิดขึ้นในไฟล์ได้ ฉันจะทำสิ่งนั้นได้อย่างไร


ไม่ชัดเจนว่าควรจับคู่คำทั้งคีย์และค่าของข้อมูล JSON หรือไม่เช่น{ "key": "the key" }ควรนับสตริงkeyหนึ่งหรือสองครั้ง
Kusalananda

คำตอบ:


45
$ tr ' ' '\n' < FILE | grep WORD | wc -l

โดยtrแทนที่ช่องว่างด้วยการขึ้นบรรทัดใหม่ให้grepกรองบรรทัดผลลัพธ์ทั้งหมดที่ตรงกับ WORD และwcนับจำนวนที่เหลือ

หนึ่งสามารถบันทึกwcส่วนโดยใช้-cตัวเลือกของ grep:

$ tr ' ' '\n' < FILE | grep -c WORD

-cตัวเลือกที่ถูกกำหนดโดย POSIX

หากไม่รับประกันว่ามีช่องว่างระหว่างคำคุณต้องใช้อักขระอื่น (เป็นตัวคั่น) เพื่อแทนที่ ตัวอย่างเช่นtrชิ้นส่วนทางเลือกคือ

tr '"' '\n'

หรือ

tr "'" '\n'

หากคุณต้องการแทนที่เครื่องหมายคำพูดคู่หรือคำเดี่ยว แน่นอนคุณยังสามารถใช้trเพื่อแทนที่อักขระหลายตัวพร้อมกัน (คิดว่าช่องว่างและเครื่องหมายวรรคตอนต่าง ๆ )

ในกรณีที่คุณต้องการนับ WORD แต่ไม่ใช่ prefixWORD, WORDsuffix หรือ prefixWORDsuffix คุณสามารถใส่รูปแบบ WORD ในเครื่องหมายเริ่มต้น / สิ้นสุดของบรรทัด:

grep -c '^WORD$'

ซึ่งเทียบเท่ากับเครื่องหมายคำเริ่มต้น / สิ้นสุดในบริบทของเรา:

grep -c '\<WORD\>'

จะทำอย่างไรถ้าไม่มีช่องว่างเช่นชื่อฟิลด์ล้อมรอบด้วยเครื่องหมายคำพูด เช่น "field"
mythz

@mythz: จากนั้นคุณแทนที่คำพูดด้วย newlines ด้วย tr ฉันจะอัปเดตคำตอบ
maxschlepzig

1
คำตอบนี้ไม่ถูกต้องในหลาย ๆ เป็นเรื่องคลุมเครือ: คุณควรอธิบายวิธีใช้trคำสั่งที่ทำงานแทนการแนะนำตัวอย่างที่จะไม่ทำงานในทุกสถานการณ์ นอกจากนี้ยังจะจับคู่คำที่มีคำที่คุณต้องการ การgrep -o '\<WORD\>' | wc -lแก้ปัญหานั้นเหนือกว่ามาก
sam hocevar

1
@Sam คำถามเปิดทิ้งหากคำค้นหาควรค้นหาเช่น 'WORD' หรือ '\ <WORD \>' - คุณสามารถอ่านได้ทั้งสองวิธี แม้ว่าคุณจะอ่านมันในวิธีที่ 2 และในทางที่ 2 เท่านั้นคำตอบของฉันจะไม่ถูกต้องในทางเดียวเท่านั้น ;) และทางออก 'grep -o' นั้นยอดเยี่ยมกว่าหากรองรับตัวเลือก -o - ซึ่งไม่ได้ระบุโดย POSIX ... ดีฉันไม่คิดว่าการใช้ tr เป็นสิ่งแปลกใหม่ที่จะเรียกมันว่า คลุมเครือ ...
maxschlepzig

1
@ Kusalananda ก็ยังคงเกิดขึ้น แต่ถ้าคุณไม่ต้องการนับการจับคู่สตริงย่อยนั้นโปรดอ่านย่อหน้าสุดท้ายของคำตอบและความคิดเห็นก่อนหน้าของฉันที่นี่
maxschlepzig

24

ด้วย GNU grep สิ่งนี้ใช้ได้ผล: grep -o '\<WORD\>' | wc -l

-o พิมพ์แต่ละส่วนที่ตรงกันของแต่ละบรรทัดในบรรทัดแยก

\<ยืนยันจุดเริ่มต้นของคำและ\>ยืนยันจุดสิ้นสุดของคำ (คล้ายกับ Perl ของ\b) เพื่อให้แน่ใจว่าคุณไม่ได้จับคู่สตริงตรงกลางคำ

ตัวอย่างเช่น,

$ python -c 'นำเข้าสิ่งนี้' | grep '\ <one \>'
ควรจะมีหนึ่ง - และโดยเฉพาะเพียงหนึ่งวิธี --obvious ที่จะทำมัน
Namespaces เป็นหนึ่งในแนวคิดที่ยอดเยี่ยม - ลองทำสิ่งเหล่านี้ให้มากขึ้น!
$ python -c 'นำเข้าสิ่งนี้' | grep -o '\ <one \>'
 one 
one 
one 
$ python -c 'นำเข้าสิ่งนี้' | grep -o '\ <one \>' | ห้องสุขา -l
3

1
หรือเพียงแค่grep -wo WORD | wc -l
Stéphane Chazelas

10

นี้น่าเสียดายที่ไม่ได้ทำงานกับ coreutilsGNU

grep -o -c WORD file

หากใช้งานได้บนแพลตฟอร์มของคุณมันเป็นโซลูชันที่สวยงามและใช้งานง่าย แต่คน GNU ยังคงคิด


2
ความผิดพลาดของฉันยังคงเปิดอยู่: savannah.gnu.org/bugs/?33080
tripleee

1
น่าเสียดายที่นี่น่าจะหรูหราที่สุด
MasterScrat

สิ่งนี้ได้ผลสำหรับฉัน!
ThisaruG

นี่เป็นสิ่งที่ผิด สิ่งนี้นับจำนวนบรรทัดด้วยรูปแบบ WORD OP ต้องการจำนวนการเกิดทั้งหมด
Pierre B

@PierreB นั่นเป็นเหตุผลที่ฉันพูดว่า GNU grepมีข้อผิดพลาดที่นี่ ยังไม่ชัดเจนจาก POSIX ความหมายของการรวมกัน-cและ-oควรเป็นเช่นนี้ในปัจจุบันไม่สามารถพกพาได้ ขอบคุณสำหรับความคิดเห็น; ฉันได้อัปเดตคำตอบนี้แล้ว
tripleee

7
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

คำสั่งนี้ทำสิ่งต่อไปนี้:

  1. แทนอักขระที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมดด้วยช่องว่าง
  2. ตัวแบ่งบรรทัดทั้งหมดจะถูกแปลงเป็นช่องว่างด้วย
  3. ลดช่องว่างหลายช่องทั้งหมดให้เป็นหนึ่งช่องว่าง
  4. ช่องว่างทั้งหมดจะถูกแปลงเป็นตัวแบ่งบรรทัด แต่ละคำในหนึ่งบรรทัด
  5. แปลคำทั้งหมดเป็นตัวพิมพ์เล็กเพื่อหลีกเลี่ยง 'Hello' และ 'hello' เป็นคำอื่น
  6. เรียงลำดับข้อความ
  7. นับและลบบรรทัดที่เท่ากัน
  8. เรียงลำดับย้อนกลับเพื่อนับคำที่พบบ่อยที่สุด
  9. เพิ่มหมายเลขบรรทัดให้กับแต่ละคำเพื่อที่จะทราบถึงคำว่าตำแหน่งทั้งหมด

ตัวอย่างเช่นถ้าฉันต้องการวิเคราะห์ข้อความ Linus Torvald แรก:

จาก: torvalds@klaava.Helsinki.FI (กลุ่มข่าว Linus Benedict Torvalds): comp.os.minix หัวเรื่อง: คุณอยากเห็นอะไรใน minix มากที่สุด? สรุป: แบบสำรวจขนาดเล็กสำหรับระบบปฏิบัติการใหม่ของฉันข้อความ -ID: <1991Aug25.205708.9541@klaava.Helsinki.FI> วันที่: 25 ส.ค. 91 20:57:08 GMT องค์กร: มหาวิทยาลัยเฮลซิงกิ

สวัสดีทุกคนที่อยู่ที่นั่นโดยใช้ minix -

ฉันกำลังทำระบบปฏิบัติการ (ฟรี) (แค่งานอดิเรกไม่ใหญ่และเป็นมืออาชีพอย่าง gnu) สำหรับโคลนนิ่ง AT 386 (486) ตัว สิ่งนี้ได้ทำการหมักมาตั้งแต่เดือนเมษายนและเริ่มเตรียมพร้อมแล้ว ฉันต้องการความคิดเห็นใด ๆ เกี่ยวกับสิ่งที่ผู้คนชอบ / ไม่ชอบใน minix เพราะระบบปฏิบัติการของฉันคล้ายกับมัน (รูปแบบทางกายภาพเดียวกันของระบบไฟล์ (เนื่องจากเหตุผลเชิงปฏิบัติ) เหนือสิ่งอื่นใด)

ขณะนี้ฉันได้ย้ายพอร์ตทุบตี (1.08) และ gcc (1.40) และสิ่งต่าง ๆ ดูเหมือนจะใช้ได้ นี่ก็หมายความว่าฉันจะได้รับบางสิ่งบางอย่างในทางปฏิบัติภายในไม่กี่เดือนและฉันอยากจะรู้ว่าคุณลักษณะส่วนใหญ่ที่คนต้องการ ข้อเสนอแนะใด ๆ ยินดีต้อนรับ แต่ฉันจะไม่สัญญาว่าจะใช้พวกเขา🙂

Linus (torvalds@kruuna.helsinki.fi)

PS ใช่ - ไม่มีโค้ด minix ใด ๆ และมี fs แบบมัลติเธรด มันไม่สามารถป้องกันได้ (ใช้การสลับงาน 386 ฯลฯ ) และอาจจะไม่สนับสนุนสิ่งอื่นใดนอกจาก AT-harddisks เพราะนั่นคือทั้งหมดที่ฉันมี :-(

ฉันสร้างไฟล์ชื่อlinus.txtฉันวางเนื้อหาแล้วฉันเขียนในคอนโซล:

sed -e 's/[^[:alpha:]]/ /g' linus.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

เอาออกจะเป็น:

 1        7 i
 2        5 to
 3        5 like
 4        5 it
 5        5 and
 6        4 minix
 7        4 a
 8        3 torvalds
 9        3 of
10        3 helsinki
11        3 fi
12        3 any
13        2 would
14        2 won
15        2 what
16        ...

หากคุณต้องการเห็นภาพเพียง 20 คำแรก:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | head -n 20

เป็นสิ่งสำคัญที่จะทราบว่าคำสั่งTR 'AZ' 'a-z'ไม่ suport UTF-8 ยังเพื่อที่ว่าในภาษาต่างประเทศ Apres คำว่าจะได้รับการแปลเป็น apres

หากคุณต้องการค้นหาคำเพียงคำเดียวคุณสามารถเพิ่ม grep ได้ในตอนท้าย:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\sword_to_search_for$"

ในสคริปต์ชื่อsearch_freq :

#!/bin/bash
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\s$1$"

ต้องเรียกใช้สคริปต์:

 search_freq word_to_search_for

sed: -e expression #2, char 7: unterminated s 'command` เช่นนี้นับทุกคำใช่มั้ย แต่ OP ถามเพียงอันเดียว คำอธิบายเล็กน้อยก็น่าจะดี
phk

ขอโทษฉันมีข้อผิดพลาด ฉันได้ทำใหม่คำสั่งและแสดงความคิดเห็นคำตอบ ในความคิดของฉันจากคำถามที่เป็นไปไม่ได้ที่จะรู้ว่าเขาต้องการได้รับ ocurrency เพียงหนึ่งคำหรือความถี่ของการเกิดขึ้น แต่ในกรณีที่คุณต้องการได้คำเดียวคุณสามารถเพิ่ม grep ได้ในตอนท้าย
Roger Borrell

3

ขึ้นอยู่กับว่าคุณต้องการจับคู่คำในคีย์หรือในค่าของข้อมูล JSON คุณมีแนวโน้มที่จะต้องการดึงเฉพาะคีย์หรือค่าจากข้อมูลเท่านั้น ไม่เช่นนั้นคุณอาจนับคำได้หลายครั้งเกินไปหากคำนั้นเป็นทั้งคีย์และค่า

ในการแยกคีย์ทั้งหมด:

jq -r '..|objects|keys[]' <file.json

สิ่งนี้เป็นการทดสอบซ้ำว่าสิ่งปัจจุบันเป็นวัตถุหรือไม่และจะแยกกุญแจออกหรือไม่ ผลลัพธ์จะเป็นรายการของคีย์หนึ่งรายการต่อบรรทัด

ในการแยกค่าทั้งหมด:

jq -r '..|scalars' <file.json

สิ่งนี้ทำงานในลักษณะที่คล้ายกัน แต่มีขั้นตอนน้อยกว่า

จากนั้นคุณสามารถไพพ์เอาต์พุตข้างต้นผ่านgrep -c 'PATTERN'(เพื่อจับคู่รูปแบบบางอย่างกับคีย์หรือค่า) หรือgrep -c -w -F 'WORD'(เพื่อจับคู่คำในคีย์หรือค่า) หรือgrep -c -x -F 'WORD'(เพื่อจับคู่คีย์หรือค่าที่สมบูรณ์) หรือคล้ายกันเพื่อ ทำการนับของคุณ


0

ฉันมี json กับสิ่งนี้: "number":"OK","number":OK"ทำซ้ำหลายครั้งในหนึ่งบรรทัด

เคาน์เตอร์ "ตกลง" เรียบง่ายของฉัน:

sed "s|,|\n|g" response | grep -c OK


-1

ฉันใช้คำสั่ง awk ด้านล่างเพื่อค้นหาจำนวนครั้งที่เกิดขึ้น

ไฟล์ตัวอย่าง

cat file1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

คำสั่ง:

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

เอาท์พุต

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

5

awk '{sum+=gsub("praveen","")} END {print sum+0}'หรือเพียงแค่
G-Man พูดว่า 'Reinstate Monica'

ให้ฉันรู้ว่าทำไมการลงคะแนนสำหรับคำตอบของฉัน
Praveen Kumar BS
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.