Как подсчитать количество вхождений слова в текстовый файл с помощью командной строки?

43

У меня есть большой файл JSON, который находится в одной строке, и я хочу использовать командную строку, чтобы иметь возможность подсчитать количество вхождений слова в файле. Как я могу это сделать?

mythz
источник
Неясно, должно ли слово соответствовать в ключах и значениях данных JSON, то есть { "key": "the key" }следует ли считать строку keyодин или два раза.
Кусалананда

Ответы:

46
$ 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\>'
maxschlepzig
источник
что если пробелов нет, то есть имя поля заключено в кавычки? например, "поле"
Мифз
@mythz: Затем вы заменяете кавычки символами новой строки на tr. Я обновлю ответ.
maxschlepzig
1
Этот ответ неверен во многих отношениях. Это расплывчато: вы должны объяснить, как придумать trкоманду, которая выполняет эту работу, вместо того, чтобы предлагать примеры, которые никогда не будут работать во всех ситуациях. Он также будет соответствовать словам, которые содержат слово, которое вы ищете. grep -o '\<WORD\>' | wc -lРешение гораздо выше.
Сэм Хоцевар
1
@ Сам, вопрос остается открытым: если искомое слово нужно искать как «WORD» или «\ <WORD \>», вы можете прочитать его обоими способами. Даже если вы прочитаете это 2-ой путь и только 2-ой путь, тогда мой ответ был бы только неправильным в 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 '\ <one \>'
 один 
один 
один 
$ python -c 'импортировать это' | grep -o '\ <one \>' | туалет
3
ephemient
источник
1
Или простоgrep -wo WORD | wc -l
Стефан Шазелас
10

Это, к сожалению , не работает с GNU coreutils.

grep -o -c WORD file

Если он работает на вашей платформе, это элегантное и довольно интуитивное решение; но люди GNU все еще думают.

tripleee
источник
2
Мое плохое, ошибка все еще открыта: savannah.gnu.org/bugs/?33080
tripleee
1
Жаль, что это было бы самым элегантным
MasterScrat
Это сработало для меня!
ThisaruG
Это не правильно. Это подсчитывает количество строк с шаблоном WORD. ОП хочет общее количество вхождений.
Пьер Б
@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. Добавьте номер строки к каждому слову, чтобы узнать значение слова в целом

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

От: torvalds@klaava.Helsinki.FI (Линус Бенедикт Торвальдс) Группы новостей: comp.os.minix Тема: Что бы вы хотели увидеть больше всего в minix? Краткое описание: небольшой опрос для моей новой операционной системы. Идентификатор сообщения: <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. Да - он свободен от любого кода minix и имеет многопоточный 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.

Если вы хотите искать только одно слово, вы можете добавить в конце команду 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`, это также подсчитывает все слова, верно? Но ОП задал только конкретный. Также немного объяснений было бы неплохо.
phk
Извините, я ошибся. Я переделал команду плюс прокомментировал ответ. По моему мнению, из вопроса невозможно узнать, хотел бы он получить вхождение только одного слова или частоту встречаемости. Но если вы хотите получить только одно слово, вы можете добавить grep в конце.
Роджер Боррелл
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

Khazad-dum_miner
источник
-1

Я использовал ниже команду awk, чтобы найти количество вхождений

файл примера

кошка 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 говорит «Восстановить Монику»
Дайте мне знать, почему голосуйте за мой ответ
Правин Кумар Б.С.