Làm cách nào để tôi đếm số lần xuất hiện của một từ trong tệp văn bản với dòng lệnh?


43

Tôi có một tệp JSON lớn nằm trên một dòng và tôi muốn sử dụng dòng lệnh để có thể đếm số lần xuất hiện của một từ trong tệp. Làm thế nào tôi có thể làm điều đó?


Không rõ liệu từ này có được khớp trong cả khóa và giá trị của dữ liệu JSON hay không, tức là có { "key": "the key" }nên đếm chuỗi keymột hoặc hai lần hay không.
Kusalananda

Câu trả lời:


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

Khi trthay thế khoảng trắng bằng dòng mới, greplọc tất cả các dòng kết quả khớp với WORD và wcđếm các dòng còn lại.

Người ta thậm chí có thể lưu wcphần bằng cách sử dụng -ctùy chọn của grep:

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

Các -ctùy chọn được định nghĩa bởi POSIX.

Nếu không đảm bảo rằng có khoảng trắng giữa các từ, bạn phải sử dụng một số ký tự khác (như dấu phân cách) để thay thế. Ví dụ các trbộ phận thay thế là

tr '"' '\n'

hoặc là

tr "'" '\n'

nếu bạn muốn thay thế dấu ngoặc kép hoặc đơn. Tất nhiên, bạn cũng có thể sử dụng trđể thay thế nhiều ký tự cùng một lúc (nghĩ các loại khoảng trắng và dấu chấm câu khác nhau).

Trong trường hợp bạn cần đếm WORD nhưng không phải tiền tốWORD, WORDsuffix hoặc tiền tốWORDsuffix, bạn có thể đặt mẫu WORD trong các điểm đánh dấu bắt đầu / cuối dòng:

grep -c '^WORD$'

Tương đương với các từ bắt đầu / kết thúc, trong ngữ cảnh của chúng tôi:

grep -c '\<WORD\>'

Điều gì nếu không có khoảng trắng, tức là tên trường được bao quanh bởi dấu ngoặc kép? ví dụ: "lĩnh vực"
huyền thoại

@mythz: Sau đó, bạn thay thế dấu ngoặc kép bằng dòng mới bằng tr. Tôi sẽ cập nhật câu trả lời.
maxschlepzig

1
Câu trả lời này không chính xác theo nhiều cách. Thật mơ hồ: bạn nên giải thích làm thế nào để đưa ra một trlệnh thực hiện công việc thay vì đề xuất các ví dụ sẽ không bao giờ hoạt động trong mọi tình huống. Nó cũng sẽ khớp với các từ có chứa từ bạn đang tìm kiếm. Các grep -o '\<WORD\>' | wc -lgiải pháp là cao hơn nhiều so.
sam hocevar

1
@Sam, câu hỏi để nó mở, nếu một từ được tìm kiếm nên được tìm kiếm như 'WORD' hoặc '\ <WORD \>' - bạn có thể đọc cả hai cách. Ngay cả khi bạn đọc nó theo cách thứ 2 và chỉ theo cách thứ 2, thì câu trả lời của tôi sẽ chỉ không chính xác theo 1 cách. ;) Và giải pháp 'grep -o' chỉ vượt trội, nếu nó hỗ trợ tùy chọn -o - không được chỉ định bởi POSIX ... Chà, tôi không nghĩ rằng việc sử dụng tr là kỳ lạ để gọi nó mơ hồ ...
maxschlepzig

1
@Kusalananda, tốt, nó vẫn còn xảy ra. Nhưng nếu bạn không muốn tính các kết hợp chuỗi con như vậy thì vui lòng đọc đoạn cuối câu trả lời của tôi và nhận xét trước đây của tôi ở đây.
maxschlepzig

24

Với GNU grep, điều này hoạt động: grep -o '\<WORD\>' | wc -l

-o in từng phần phù hợp của từng dòng trên một dòng riêng biệt.

\<xác nhận bắt đầu của một từ và \>khẳng định kết thúc của một từ (tương tự như của Perl \b), vì vậy điều này đảm bảo rằng bạn không khớp một chuỗi ở giữa một từ.

Ví dụ,

$ python -c 'nhập cái này' | grep '\ <một \>'
Nên có một - và tốt nhất là chỉ có một cách rõ ràng để làm điều đó.
Không gian tên là một ý tưởng tuyệt vời - hãy làm nhiều hơn nữa!
$ python -c 'nhập cái này' | grep -o '\ <one \>'
 one 
one 
one 
$ python -c 'nhập cái này' | grep -o '\ <một \>' | wc -l
3

1
Hoặc chỉgrep -wo WORD | wc -l
Stéphane Chazelas

10

Thật không may, điều này không hoạt động với GNU coreutils.

grep -o -c WORD file

Nếu nó hoạt động trên nền tảng của bạn, thì đó là một giải pháp thanh lịch và khá trực quan; nhưng những người GNU vẫn đang suy nghĩ.


2
Thật

1
Quá tệ, điều này sẽ trở nên thanh lịch nhất
MasterScrat

Điều này làm việc cho tôi!
ThisaruG

Cái này sai. Điều này đếm số lượng dòng với mẫu WORD. OP muốn tổng số lần xuất hiện.
Pierre B

@PierreB Đó là lý do tại sao tôi nói GNU grepcó lỗi ở đây. Không rõ POSIX là gì về ngữ nghĩa của việc kết hợp -c-onên nó không phải là di động. Cảm ơn các bình luận; Tôi đã cập nhật câu trả lời này.
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 

Lệnh này thực hiện như sau:

  1. Thay thế tất cả các ký tự không chữ và số với một khoảng trắng.
  2. Tất cả các ngắt dòng cũng được chuyển đổi thành không gian.
  3. Giảm tất cả nhiều khoảng trống thành một khoảng trống
  4. Tất cả các không gian bây giờ được chuyển đổi để ngắt dòng. Mỗi từ trong một dòng.
  5. Dịch tất cả các từ sang chữ thường để tránh 'Xin chào' và 'xin chào' thành các từ khác nhau
  6. Sắp xếp văn bản
  7. Đếm và loại bỏ các dòng bằng nhau
  8. Sắp xếp ngược lại để đếm những từ thường xuyên nhất
  9. Thêm một số dòng cho mỗi từ để biết toàn bộ từ tích cực

Ví dụ: nếu tôi muốn phân tích thông điệp Linus Torvald đầu tiên:

Từ: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) Nhóm tin: comp.os.minix Chủ đề: Bạn muốn thấy gì nhất trong minix? Tóm tắt: cuộc thăm dò nhỏ cho hệ điều hành mới của tôi ID tin nhắn: <1991Aug25.205708.9541@klaava.Helsinki.FI> Ngày: 25 tháng 8 91 20:57:08 GMT Tổ chức: Đại học Helsinki

Xin chào mọi người ngoài kia bằng cách sử dụng minix -

Tôi đang làm một hệ điều hành (miễn phí) (chỉ là một sở thích, sẽ không lớn và chuyên nghiệp như gnu) cho các bản sao AT (486) AT. Điều này đã được ủ từ tháng tư, và bắt đầu sẵn sàng. Tôi muốn bất kỳ phản hồi nào về những thứ mọi người thích / không thích trong minix, vì HĐH của tôi giống với nó một chút (cùng bố cục vật lý của hệ thống tệp (vì lý do thực tế) trong số những thứ khác).

Tôi hiện đã chuyển bash (1.08) và gcc (1.40) và mọi thứ dường như hoạt động. Điều này ngụ ý rằng tôi sẽ nhận được một cái gì đó thiết thực trong vòng một vài tháng và tôi muốn biết những tính năng mà hầu hết mọi người sẽ muốn. Mọi lời đề nghị đều được chào đón, nhưng tôi sẽ không hứa sẽ thực hiện chúng

Linus (torvalds@kruuna.helsinki.fi)

Tái bút Có - nó không có bất kỳ mã minix nào và nó có fs đa luồng. Nó KHÔNG đáng tin cậy (sử dụng chuyển đổi tác vụ 386, v.v.) và có lẽ nó sẽ không bao giờ hỗ trợ bất cứ thứ gì ngoài AT-harddisks, vì đó là tất cả những gì tôi có :-(.

Tôi tạo một tệp có tên linus.txt , tôi dán nội dung và sau đó tôi viết trong bảng điều khiển:

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

Đặt ra sẽ là:

 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        ...

Nếu bạn muốn hình dung chỉ 20 từ đầu tiên:

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

Quan trọng là phải lưu ý rằng lệnh tr 'AZ' 'a-z' không suport UTF-8 chưa , do đó bằng tiếng nước ngoài các Apres từ sẽ được dịch là Apres.

Nếu bạn chỉ muốn tìm kiếm sự xuất hiện của một từ, bạn có thể thêm một grep ở cuối:

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$"

Trong một tập lệnh gọi là 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$"

Kịch bản phải được gọi:

 search_freq word_to_search_for

sed: -e expression #2, char 7: unterminated s 'lệnh`, điều này cũng đếm tất cả các từ, phải không? Nhưng OP chỉ hỏi một người cụ thể. Ngoài ra một chút giải thích sẽ tốt đẹp.
phk

Xin lỗi tôi đã có một sai lầm. Tôi đã làm lại lệnh cộng với nhận xét câu trả lời. Theo ý kiến ​​của tôi, từ câu hỏi, không thể biết được anh ấy muốn có được số tiền chỉ bằng một từ hay tần suất xuất hiện. Nhưng trong trường hợp bạn chỉ muốn nhận một từ, bạn có thể thêm một grep ở cuối.
Roger Borrell

3

Tùy thuộc vào việc bạn muốn khớp từ trong các khóa hoặc trong các giá trị của dữ liệu JSON, bạn có thể muốn trích xuất chỉ các khóa hoặc chỉ các giá trị từ dữ liệu. Nếu không, bạn có thể đếm một số từ quá nhiều lần nếu chúng xuất hiện dưới dạng cả khóa và giá trị.

Để giải nén tất cả các khóa:

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

Điều này đệ quy kiểm tra xem vật hiện tại có phải là một đối tượng hay không và nếu có, nó sẽ trích xuất các khóa. Đầu ra sẽ là một danh sách các khóa, mỗi khóa một dòng.

Để trích xuất tất cả các giá trị:

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

Điều này hoạt động theo cách tương tự, nhưng có ít bước hơn.

Sau đó, bạn có thể chuyển đầu ra của phần trên qua grep -c 'PATTERN'(để khớp một số mẫu với các khóa hoặc giá trị) hoặc grep -c -w -F 'WORD'(để khớp một từ trong các khóa hoặc giá trị) hoặc grep -c -x -F 'WORD'(để khớp với một khóa hoặc giá trị hoàn chỉnh) hoặc tương tự, với đếm của bạn


0

Tôi có json với một cái gì đó như thế này: "number":"OK","number":OK"lặp đi lặp lại nhiều lần trong một dòng.

Bộ đếm "OK" đơn giản của tôi:

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


-1

tôi đã sử dụng lệnh awk dưới đây để tìm số lần xuất hiện

tập tin ví dụ

tập tin mèo1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

chỉ huy:

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

đầu ra

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

5

Hoặc chỉ awk '{sum+=gsub("praveen","")} END {print sum+0}'.
G-Man nói 'Tái lập Monica'

Hãy cho tôi biết lý do tại sao bỏ phiếu cho câu trả lời của tôi
Praveen Kumar BS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.