Wyklucz podkatalog za pomocą funkcji find


115

Mam taką strukturę katalogów

data
|___
   |
   abc
    |____incoming
   def
    |____incoming
    |____processed
   123
    |___incoming
   456
    |___incoming
    |___processed

We wszystkich folderach w katalogu Data znajduje się przychodzący podfolder. Chcę pobrać wszystkie pliki ze wszystkich folderów i podfolderów z wyjątkiem katalogów def / incoming i 456 / incoming. Wypróbowałem za pomocą następującego polecenia

 find /home/feeds/data -type d \( -name 'def/incoming' -o -name '456/incoming' -o -name arkona \) -prune -o -name '*.*' -print

ale nie działa zgodnie z oczekiwaniami.

Ravi


3
To nie jest dobra rada, ale szybko i nieprzyjemnie wyciągnie cię z wielu sytuacji: odpuść to, grep -v somethingaby wykluczyć to, czego nie chcesz
Miquel

Odpowiedzi:


206

To działa:

find /home/feeds/data -type f -not -path "*def/incoming*" -not -path "*456/incoming*"

Wyjaśnienie:

  • find /home/feeds/data: zacznij szukać rekurencyjnie od określonej ścieżki
  • -type f: znajdź tylko pliki
  • -not -path "*def/incoming*": nie uwzględniaj niczego def/incomingjako części swojej ścieżki
  • -not -path "*456/incoming*": nie uwzględniaj niczego 456/incomingjako części swojej ścieżki

otrzymywanie błędu „find: bad option -not find: path-list predicate-list”
Ravi

@Ravi czy używasz powłoki bash? Właśnie przetestowałem to na moim terminalu i działa dla mnie. Spróbuj skopiować i wkleić rozwiązanie, jeśli wprowadziłeś modyfikacje w skrypcie.
sampson-chen

Działa, ale wyświetla katalogi, a nie pliki w tych katalogach.
Ravi

1
-pathpasuje do całego ciągu, więc jeśli robisz find ., twoje -pathstruny muszą być./path/to/directory/*
Heath Borders

1
FYI na -not -pathpewno zadziała w tym przykładzie, ale findnadal iteruje w strukturze katalogów i używa cykli procesora do iteracji po wszystkich tych katalogach / plikach. aby zapobiec finditeracji po tych katalogach / plikach (być może są tam miliony plików), musisz użyć -prune( -pruneopcja jest jednak trudna w użyciu).
Trevor Boyd Smith

9

Tylko ze względu na dokumentację: być może będziesz musiał kopać głębiej, ponieważ istnieje wiele konstelacji wyszukiwania i przeskakiwania (tak jak musiałem). Może się okazać, że pruneto twój przyjaciel, a -not -pathnie zrobi tego, czego oczekujesz.

Oto cenny przykład 15 przykładów wyszukiwania, które wykluczają katalogi:

http://www.theunixschool.com/2012/07/find-command-15-examples-to-exclude.html

Aby połączyć się z początkowym pytaniem, wykluczanie w końcu zadziałało dla mnie w ten sposób:

find . -regex-type posix-extended -regex ".*def/incoming.*|.*456/incoming.*" -prune -o -print 

Następnie, jeśli chcesz znaleźć jeden plik i nadal wykluczyć ścieżki, po prostu dodaj | grep myFile.txt.

Może to również zależeć od znalezionej wersji. Widzę:

$ find -version
GNU find version 4.2.27
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION SELINUX

5

-namepasuje tylko do nazwy pliku, a nie do całej ścieżki. Zamiast tego chcesz użyć -pathdla części, w których przycinasz katalogi, takie jak def/incoming.


2
find $(INP_PATH} -type f -ls |grep -v "${INP_PATH}/.*/"

7
Niektóre wyjaśnienia mogą sprawić, że będzie to znacznie lepsza odpowiedź.
Cris Luengo,

Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną krótkoterminową pomoc. Właściwe wyjaśnienie znacznie poprawiłoby jego długoterminową wartość, pokazując, dlaczego jest to dobre rozwiązanie problemu i uczyniłoby go bardziej użytecznym dla przyszłych czytelników z innymi, podobnymi pytaniami. Edytuj swoją odpowiedź, dodając wyjaśnienie, w tym przyjęte przez siebie założenia
Shawn C.

1
Uwaga: ta sztuczka nie działa, jeśli używa się go find ... -print0w połączeniu z późniejszymxargs -0
phs

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.