2014-04-21 17 views
23

Muszę znaleźć (lub dokładniej policzyć) wszystkie pliki, które pasują do tego wzorca.Rekursywnie znaleźć wszystkie pliki, które pasują do określonego wzorca

*/foo/* doc

Jeżeli pierwsza wieloznaczny gwiazdka obejmuje zmienną liczbę podkatalogów.

+1

Czy to musi być bash? zsh może to zrobić, używając składni 'ls **/foo/* .doc'. – Alastair

+0

Alastair, dzięki za sugestię. Nie wiedziałem o zsh i jego podwójnej składni. Co ciekawe, wynikowa rozszerzona lista argumentów jest zbyt długa dla ls (około 6000 nazw plików) i daje błąd. – pw222

+0

Bash v4 obsługuje także rekurencyjny glob "**". – tripleee

Odpowiedz

27

GNU znaleźć można użyć wyrażenia regularnego, które (w przeciwieństwie -name) pasujące całą ścieżkę:

find . -regex '.*/foo/[^/]*.doc' 

po prostu policzyć liczbę plików:

find . -regex '.*/foo/[^/]*.doc' -printf '%i\n' | wc -l 

(Przyczyny kod formatu %ifind, aby wydrukować numer i-węzła zamiast nazwy pliku, w przeciwieństwie do nazwy pliku, numer i-węzła gwarantuje, że nie będzie miał znaków takich jak znak nowej linii, więc liczenie jest bardziej wiarygodne. Dzięki @tripleee za sugestię.)

Nie wiem, czy to zadziała na OSX.

+2

Dołącz "| wc -l" na koniec tego i jest idealny. – pw222

8

jak about:

find BASE_OF_SEARCH/*/foo -name \*.doc -type f | wc -l

Co to robi:

  • zaczynają się BASE_OF_SEARCH katalogu/
  • wygląd we wszystkich katalogów, które mają Foo katalogu
  • szukać plików o nazwie jak * .doc
  • policz linie o f wyniku (jeden na plik)

Zaletą tej metody:

  • nie rekurencyjne ani iteracyjne (bez pętli)
  • jest to łatwe do odczytania, a jeśli uwzględnić go w skrypcie jest dość łatwy do rozszyfrowania (regex czasami nie jest).

AKTUALIZACJA: potrzebujesz zmiennej głębokości? ok:

find BASE_OF_SEARCH -name \*.doc -type f | grep foo | wc -l

  • start na BASE_OF_SEARCH katalogu
  • szukać plików o nazwach takich jak * .doc
  • pokazać tylko linie tego wyniku, które zawierają "foo"
  • policzyć wiersze wynik (jeden na plik)

Opcjonalnie można odfiltrować wyniki, które mają "foo" w pliku imię i nazwisko, ponieważ pokaże to również.

+0

Działa to z wyjątkiem faktu, że nie działa z głębokością podkatalogu zmiennej pomiędzy BASE_OF_SEARCH a foo. Być może nie byłem wystarczająco jasny z tą specyfikacją. Jest na tyle blisko, że mogłem wykonać zadanie, które zamierzałem wykonać, a więc przegłosować i podziękować. – pw222

+0

Należy podkreślić, że nie jest rekurencyjny. Jednak często nie jest to konieczne. To jest proste i sympatyczne rozwiązanie. Choć może to mieć problemy z wydajnością - nie wiem. – robsch

+0

Dodałem funkcję dla Twoich żądań – MonkeyWidget

2

Nietestowane, ale spróbuj:

find . -type d -name foo -print | while read d; do echo "$d/*.doc" ; done | wc -l 

znaleźć wszystkie „foo” katalogów (na różnych głębokościach) (ta ignoruje dowiązania, jeśli jest to część problemu można dodać je); użyj globowania powłoki, aby znaleźć wszystkie pliki ".doc", a następnie policz je.

+0

Pętla 'while' jest w pełni redundantna i nieco podatna na błędy. Ponadto symbol wieloznaczny nie zostanie rozwinięty, ponieważ jest cytowany. Po prostu wpisz 'find -print' na' wc -l'. Będzie to jednak powodować niepoprawną liczbę, jeśli nazwa pliku zawiera znak nowej linii. – tripleee

Powiązane problemy