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


10

Как бы вы посчитали каждое вхождение термина во всех файлах в текущем каталоге? - и подкаталоги (?)

Я читал, что для этого вы бы использовали grep; какая точная команда?

Кроме того, возможно ли это с какой-то другой командой?

Ответы:


12

Использование grep+ wc(это будет обслуживать несколько вхождений термина в одной строке):

grep -rFo foo | wc -l
  • -rin grep: рекурсивный поиск в текущей иерархии каталогов;
  • -Fin grep: сопоставляется с фиксированной строкой, а не с шаблоном;
  • -oв grep: печатает только совпадения;
  • -lin wc: печатает количество строк;
% tree                 
.
├── dir
│   └── file2
└── file1

1 directory, 2 files
% cat file1 
line1 foo foo
line2 foo
line3 foo
% cat dir/file2 
line1 foo foo
line2 foo
line3 foo
% grep -rFo foo | wc -l
8

Я думаю, что самый хороший.
Джейкоб Влейм

1
@JacobVlijm Спасибо! Ты мне тоже нравишься (и уже проголосовал)
kos

Я думаю, что PCREsне следует использовать, так как они являются экспериментальными
Эдвард Торвальдс

2
PCRE не являются «экспериментальными», но они также не всегда компилируются в grep (именно поэтому я использую pcregrep, когда они мне нужны). В этом случае, однако, они не нужны, поскольку вопрос задается о «термине», который, скорее всего, является фиксированной строкой, а не шаблоном любого вида. Так -Fчто, вероятно, будет быстрее.
dannysauer

2
@dannysauer Я использовал PCRE, потому что по какой-то (неправильной) причине я думал, что они необходимы для соответствия нескольким вхождениям на одной линии, но на самом деле это не так. Я просто не пытался использовать -Fвместо -P. Спасибо за отличное предложение, обновление с использованием -F, которое действительно подходит лучше здесь.
Кос

8

grep -Rc [term] *сделаю это. -RФлаг означает , что вы хотите рекурсивно искать в текущем каталоге и всех его подкаталогах. Это *селектор файлов, означающий: все файлы. -cФлага делает grepвыводить только число вхождений. Однако, если слово встречается в одной строке несколько раз, оно считается только один раз.

От man grep:

  -r, --recursive
          Read all files under each directory, recursively, following symbolic links only if they are on the command line.
          This is equivalent to the -d recurse option.

   -R, --dereference-recursive
          Read all files under each directory, recursively.  Follow all symbolic links, unlike -r.

Если у вас нет символических ссылок в вашем каталоге, нет никакой разницы.


Вы можете добавить -cфлаг к grep. Тогда grep считает себя, и вам не нужноwc
Wayne_Yux

вы могли бы поставить --раньше*
Эдвард Торвальдс

2
*Будет расширяться только для не составляют скрытые, так что вы пропустите все те. Имеет больше смысла просто использовать "." так как вы все равно будете рекурсивно обрабатывать аргументы - и это получит точечные файлы. Большая проблема здесь заключается в том, что это может быть количество строк, а не количество вхождений слова. Если термин появляется несколько раз в одной строке, он будет учитываться только один раз как "grep -c"
dannysauer

2

В небольшом скрипте Python:

#!/usr/bin/env python3
import os
import sys

s = sys.argv[1]
n = 0
for root, dirs, files in os.walk(os.getcwd()):
    for f in files:
        f = root+"/"+f      
        try:
            n = n + open(f).read().count(s)
        except:
            pass
print(n)
  • Сохранить как count_string.py.
  • Запустите его из каталога с помощью команды:

    python3 /path/to/count_string.py <term>
    

Заметки

  • Если термин включает пробелы, используйте кавычки.
  • Он подсчитывает каждый вхождение термина рекурсивно, даже если несколько вхождений в одной строке.

Объяснение:

# get the current working directory
currdir = os.getcwd()
# get the term as argument
s = sys.argv[1]
# count occurrences, set start to 0 
n = 0
# use os.walk() to read recursively
for root, dirs, files in os.walk(currdir):
    for f in files:
        # join the path(s) above the file and the file itself
        f = root+"/"+f
        # try to read the file (will fail if the file is unreadable for some reason)
        try:
            # add the number of found occurrences of <term> in the file
            n = n + open(f).read().count(s)
        except:
            pass
print(n)

2
Питон парень ;) +1
TellMeWhy

1
Кстати, для чего rootи fдля чего?
TellMeWhy

1
rootпуть к файлу, включая «над» текущим каталогом, fэто файл. В качестве альтернативы os.path.join()можно использовать, но более многословно.
Джейкоб Влейм

1
А n = n + open(f).read().count(s)?
TellMeWhy

2
Похоже, что это единственный ответ, который считает все вхождения термина запрошенным OP. AFAIK, все решения, использующие grep, будут подсчитывать все строки, в которых встречается термин, поэтому строка, включающая термин три раза, будет учитываться только как одно вхождение.
Джо

2

Как вариант хорошего ответа @ kos, если вы заинтересованы в разбивке счетчиков, вы можете использовать -cпереключатель grep для подсчета вхождений:

$ grep -rFoc foo
file1:3
dir/file2:3
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.