нужна команда, чтобы найти количество уникальных слов в файле с помощью grep
Пробовал использовать grep вместе с uniq и sort, но нужно найти способ использовать только команды grep и wc. Это два способа, которыми я могу это сделать, но мне нужно использовать только grep..
$ grep -oE '\w+' 'file.txt' | sort | uniq | wc -l
$ grep -oE '\w+' 'file.txt' > temp.txt && awk '!seen[$0]++' temp.txt | wc -l
Пример входного файла:
one two three four five
two four one six
eight three seven five
Выход: уникальное количество слов: 8
Можно ли сначала извлечь слова с помощью команды grep -oE '\w+' file.txt, затем выполнить grep для каждого слова в пустой файл и добавить слово в файл, если grep не находит слово, существующее в этом файле .таким образом к нему будут добавлены только те слова, которых нет в новом файле? можно ли это сделать с помощью grep?
@AndreWildberg, я добавил ожидаемый результат
Большое спасибо! Значит, в файле есть только слова, некоторые в одной строке, но также и с символами новой строки?
@AndreWildberg да, в файле есть только слова, например абзац с несколькими строками, содержащими слова.
Кстати, 1) sort | uniq
= sort -u
и 2) grep -oE '\w+' 'file.txt' > temp.txt && awk '!seen[$0]++' temp.txt
= grep -oE '\w+' 'file.txt' | awk '!seen[$0]++'
.
почему нельзя использовать sort
? это своего рода домашнее задание/лабораторное задание, и если да, то каковы полные требования/ограничения? вы ожидаете, что сделаете все это, используя только grep
и wc
?
@markp-fuso просто пытается расширить функциональность grep без использования сортировки. Требуется просто получить количество уникальных слов в файле с помощью grep и wc, возможно, также можно использовать find
«Когда выдающийся, но пожилой учёный утверждает, что что-то возможно, он почти наверняка прав. Когда он утверждает, что что-то невозможно, он, скорее всего, ошибается».
@jhnc, честно говоря, я не рассматривал более эзотерические сценарии, которые могли бы быть возможны с помощью GNU grep и его расширений, учитывая некоторые важные предостережения!
Поскольку awk также помечен тегами, подход использует только (почти любой) awk
, возвращая длину ассоциативного массива, где индексами являются слова.
% awk '{for(i=1;i<=NF;i++){A[$i]++}} END{print length(A)}' file
8
Протестировано с
То, что вы хотите сделать, невозможно с помощью всего лишь grep
или grep
+wc
(если только вы не используете GNU grep
с его расширениями и предостережениями согласно ответу @jhnc).
Учитывая это, если вы действительно хотите использовать только один инструмент, используйте GNU Awk для многосимвольных символов RS
и примите в качестве входных данных файл, состоящий из «слов», разделенных пробелами:
$ awk -v RS='\\s+' '{unq[$0]} END{print "unique word count:", length(unq)}' file.txt
unique word count: 8
или используя регулярное выражение для идентификации «слова»:
$ awk -v RS='\\w+' 'RT{unq[RT]} END{print "unique word count:", length(unq)}' file.txt
unique word count: 8
Поскольку у вашего grep
есть -o
, я предполагаю, что у него также есть -P
и -z
:
grep -zPo '(?s)(\b\w+\b)(?!.*\b\1\b)' file.txt |
grep -zc ^
-z
, чтобы grep
рассматривал весь файл как одну «строку» (поскольку в нем не должно быть нулей)-P
, чтобы включить Perl-совместимые регулярные выражения (PCRE), которые позволяют выполнять обходные утверждения(?s)
— сообщить PCRE, что .
также должно соответствовать символу новой строки.(?!
... )
, чтобы найти последнее вхождение каждого слова (т. е. за словом, за которым не следует ничего, за которым следует само себя)
\b\w+\b
и \b\1\b
исключить части слов-o
для вывода каждого совпадения в отдельной «строке» (из-за -z
в качестве символа конца строки используются нули)Это будет очень медленно для больших файлов.
Сейчас я немного думаю о том, что делает этот сценарий. Согласно справочной странице GNU grep о -P
«Этот параметр является экспериментальным в сочетании с параметром -z (--null-data)», знаете ли вы, является ли что-либо из приведенного выше хрупким в этом контексте?
@EdMorton, учитывая, что RE страдает от катастрофического возврата, хрупкость - наименьшая из его проблем.
@EdMorton regex101 достигает 40M шагов для ввода 3500 слов и тайм-аута с 4000, намного больше, и это, скорее всего, сломается
ну, ОП только что спросил, можно ли это сделать, а не можно ли это сделать надежно, портативно, эффективно, надежно и т. д., так что, по моему мнению, это хороший ответ :-).
да, для любого ввода значительного размера просто использовать sort -u
намного надежнее
TIL -o
нет в POSIX grep
Можете ли вы добавить минимальный (5–10 строк) пример с ожидаемым результатом?