Jak policzyłbyś każde wystąpienie terminu we wszystkich plikach w bieżącym katalogu?


10

Jak policzyłbyś każde wystąpienie terminu we wszystkich plikach w bieżącym katalogu? - i podkatalogi (?)

Przeczytałem o tym, że użyłbyś tego grep; jakie jest dokładne polecenie?

Czy jest to również możliwe przy użyciu innego polecenia?

Odpowiedzi:


12

Używanie grep+ wc(pozwoli to na wielokrotne użycie terminu w tym samym wierszu):

grep -rFo foo | wc -l
  • -rin grep: wyszukuje rekurencyjnie w bieżącej hierarchii katalogów;
  • -Fin grep: dopasowuje do ustalonego ciągu zamiast do wzorca;
  • -ow grep: drukuje tylko dopasowania;
  • -lin wc: drukuje liczbę linii;
% 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

Myślę, że najładniejszy.
Jacob Vlijm,

1
@JacobVlijm Thanks! Ja też cię lubię (i już to głosowałem)
Kos,

Myślę, że PCREsnie należy go stosować, ponieważ są eksperymentalne
Edward Torvalds

2
PCRE nie są „eksperymentalne”, ale nie zawsze są też kompilowane do grep (dlatego używam pcregrep, kiedy ich potrzebuję). W tym przypadku nie są one jednak konieczne, ponieważ pytanie dotyczy „terminu”, który prawdopodobnie jest stałym ciągiem, a nie jakimkolwiek wzorem. Tak, -Fbędzie prawdopodobnie szybciej.
dannysauer,

2
@ Dannysauer Użyłem PCRE, ponieważ z jakiegoś (niewłaściwego) powodu myślałem, że są potrzebne, aby dopasować wiele wystąpień w tej samej linii, ale tak naprawdę nie są. Po prostu nie próbowałem używać -Fzamiast -P. Dzięki za świetną sugestię, aktualizację za pomocą -F, która rzeczywiście pasuje tutaj lepiej.
Kos

8

grep -Rc [term] *zrobi to. -RFlaga oznacza, że chcesz rekurencyjnie przeszukać bieżącym katalogu i wszystkich jego podkatalogów. Jest *to selektor plików, który oznacza: wszystkie pliki. -cFlag sprawia greptylko wyjście liczbę wystąpień. Jeśli jednak słowo występuje wiele razy w jednym wierszu, jest liczone tylko raz.

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

Jeśli w katalogu nie ma dowiązań symbolicznych, nie ma różnicy.


możesz dodać -cflagę do grep. Wtedy grep się liczy i nie potrzebujeszwc
Wayne_Yux

możesz chcieć --wcześniej*
Edward Torvalds

2
*Wzrośnie tylko do osób niebędących dotfiles, więc pominięcia wszystkich tych. Bardziej sensowne jest po prostu użycie „”. ponieważ i tak będziesz przetwarzał argumenty rekurencyjnie - i to dostanie pliki kropkowe. Większy problem polega na tym, że może to oznaczać liczbę wierszy, a nie liczbę wystąpień słowa. Jeśli termin pojawia się wiele razy w jednym wierszu, zostanie policzony tylko raz przez „grep -c”
dannysauer

2

W małym skrypcie 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)
  • Zapisz to jako count_string.py.
  • Uruchom go z katalogu za pomocą polecenia:

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

Notatki

  • Jeśli termin obejmuje spacje, użyj cudzysłowów.
  • Liczy się każde wystąpienie tego terminu rekurencyjnie, także w przypadku wielokrotnego wystąpienia w jednym wierszu.

Wyjaśnienie:

# 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
Facet pytona ;) +1
TellMeWhy

1
btw co to rooti fdo?
TellMeWhy,

1
rootto ścieżka do pliku, w tym „powyżej” bieżącego katalogu, fto plik. Alternatywnie, os.path.join()można użyć, ale jest bardziej szczegółowy.
Jacob Vlijm,

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

2
Wydaje się, że jest to jedyna odpowiedź, która uwzględnia wszystkie wystąpienia terminu zgodnie z żądaniem PO. AFAIK, wszystkie rozwiązania wykorzystujące grep będą liczyć wszystkie linie, w których występuje termin, więc linia zawierająca ten termin trzy razy będzie liczyła się tylko jako jedno wystąpienie.
Joe

2

Jako wariant ładnej odpowiedzi @ kos, jeśli chcesz wyszczególnić liczby, możesz użyć -cprzełącznika grep do liczenia wystąpień:

$ grep -rFoc foo
file1:3
dir/file2:3
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.