Як підрахувати кількість входів слова в текстовому файлі за допомогою командного рядка?


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, але не префікс WORD, WORDsuffix або prefixWORDsuffix, ви можете додати шаблон WORD у маркери початку / кінця рядка:

grep -c '^WORD$'

Що в нашому контексті еквівалентно маркерам початку / закінчення слова:

grep -c '\<WORD\>'

що робити, якщо пробілів немає, тобто назва поля оточена лапками? напр. "поле"
mythz

@mythz: Потім ви замінюєте лапки новими рядками на tr. Я оновлю відповідь.
maxschlepzig

1
Ця відповідь багато в чому неправильна. Це розпливчасто: слід пояснити, як придумати trкоманду, яка виконує завдання, замість того, щоб пропонувати приклади, які ніколи не працюватимуть у будь-яких ситуаціях. Він також відповідатиме словам, які містять шукане слово. grep -o '\<WORD\>' | wc -lРішення набагато вище.
sam hocevar

1
@Sam, питання залишає його відкритим, якщо в пошуковому слові слід шукати слово "WORD" або "\ <WORD \>" - ви можете прочитати його обома способами. Навіть якщо ви читаєте це другим способом і лише другим способом, то моя відповідь була б лише 1 помилковою. ;) І рішення 'grep -o' є лише вищим, якщо воно підтримує опцію -o - яке не визначено POSIX ... Ну, я не думаю, що використання tr - це екзотика, щоб назвати це смутно ...
maxschlepzig

1
@Kusalananda, ну, це все-таки явище. Але якщо ви не хочете рахувати такі збіги підрядків, будь ласка, прочитайте останній абзац моєї відповіді та мій попередній коментар тут.
maxschlepzig

24

З GNU grep це працює: grep -o '\<WORD\>' | wc -l

-o друкує всі відповідні частини кожного рядка на окремому рядку.

\<стверджує початок слова і \>стверджує кінець слова (подібно до Perl \b), так що це гарантує, що ви не збігаєте рядок у середині слова.

Наприклад,

$ python -c 'імпортувати це' | grep '\ <one \>'
Повинен бути один - і бажано лише один - очевидний спосіб це зробити.
Простори імен - це чудова ідея - давайте зробимо більше таких!
$ python -c 'імпортувати це' | Grep -o '\ <один \>'
 один 
один 
один 
$ пітон -c 'імпортувати цей' | grep -o '\ <один \>' | wc -l
3

1
Або простоgrep -wo WORD | wc -l
Стефан Шазелас

10

На жаль, це не працює з GNU coreutils.

grep -o -c WORD file

Якщо він працює на вашій платформі, це елегантне і досить інтуїтивне рішення; але люди з GNU все ще думають.


2
Мій поганий, помилка все ще відкрита: savannah.gnu.org/bugs/?33080
tripleee

1
Шкода, що це було б найелегантніше
MasterScrat

Це працювало для мене!
ThisaruG

Це неправильно. При цьому підраховується кількість рядків із зразком WORD. ОП хоче загальну кількість подій.
П’єр Б

@PierreB Ось чому я кажу, що GNU grepмає помилку тут. З POSIX незрозуміло, якою має бути семантика комбінування, -cі -oце наразі не є портативним. Дякую за коментар; Я оновив цю відповідь.
трійчатка

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. Перекладає всі слова в малі регістри, щоб уникнути "привіт" та "привіт", щоб це були різні слова
  6. Сортування тексту
  7. Підраховують і видаляють рівні лінії
  8. Сортування зворотно, щоб підрахувати найчастіші слова
  9. Додайте номер рядка до кожного слова, щоб знати слово posotion в цілому

Наприклад, якщо я хочу проаналізувати перше повідомлення Лінуса Торвальда:

Від: torvalds@klaava.Helsinki.FI (Лінус Бенедикт Торвальдс) Групи новин: comp.os.minix Тема: Що б ви найбільше хотіли бачити в minix? Короткий зміст: невелике опитування для моєї нової операційної системи ID повідомлення: <1991Aug25.205708.9541@klaava.Helsinki.FI> Дата: 25 серпня 91 20:57:08 GMT Організація: Університет Гельсінкі

Привіт всім, хто використовує minix -

Я роблю (безкоштовну) операційну систему (просто хобі, не буде великим та професійним, як gnu) для клонів 386 (486) AT. Це вариться з квітня та починає готуватися. Мені б хотілося отримати будь-які відгуки про речі, які люблять / не подобаються в minix, так як моя ОС дещо нагадує (те саме фізичне розташування файлової системи (через практичні причини), серед іншого).

Наразі я переніс bash (1,08) та gcc (1,40), і все, здається, працює. Це означає, що я отримаю щось практичне протягом декількох місяців, і я хотів би знати, які особливості хотіли б більшість людей. Будь-які пропозиції вітаються, але я не обіцяю, що я їх втілю 🙂

Лінус (torvalds@kruuna.helsinki.fi)

PS. Так - він не містить будь-якого міні-коду, і він має багатопотоковий fs. Він НЕ передбачуваний (використовує 386 переключення завдань тощо), і він, ймовірно, ніколи не підтримує нічого, крім AT-жорстких дисків, так як це все, що у мене є :-(

Я створюю файл з іменем 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

Важливо відзначити , що команда тр «AZ» «а-г» НЕ зониСкідкі UTF-8 поки , так що на іноземних мовах слово Apres б перекласти як Apres.

Якщо ви хочете шукати частоту одного слова, ви можете додати позначку в кінці:

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 "команда", також це рахує всі слова, правда? Але ОП запитав лише конкретного. Також трохи пояснень було б непогано.
phk

Вибачте, що помилився. Я переробив команду плюс прокоментував відповідь. На мою думку, з питання неможливо дізнатися, наскільки він хотів би отримати достовірність лише одного слова чи частоти випадків. Але якщо ви хочете отримати лише одне слово, ви можете додати позначку в кінці.
Роджер Боррелл

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, щоб знайти кількість подій

Приклад файлу

файл кішки1

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 каже "Відновити Моніку"

Дайте мені знати, чому голосувати за мою відповідь
Praveen Kumar BS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.