find: prune nie ignoruje określonej ścieżki

13

Muszę wykluczyć .gitz findwyszukiwania. Aby to osiągnąć, używam -path ./.git -pruneprzełącznika:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

Jednak nawet jeśli pomija to zawartość katalogu .git, zawiera on sam katalog. Działa, gdy dodam-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'

Dlaczego jest to konieczne. Pomyślałem, że oba polecenia powinny mieć takie same wyjście. Druga składnia jest dość brzydka.

Martin Vegter
źródło
4
Potrzebujesz -print, w przeciwnym razie domniemanie -printdotyczy całego warunku
Stéphane Chazelas
1
Zobacz także unix.stackexchange.com/q/102191/22565
Stéphane Chazelas

Odpowiedzi:

3

manAktualizacja finddaje:

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.

Tak więc w pierwszym przykładzie nie jest -path ./.git -pruneto nieprawdą i dlatego -printnie zostanie wywołana domyślna akcja ( ), stąd wypisywana jest linia.

Timo
źródło
22

Byłem zdezorientowany, dlaczego findkomenda drukuje również przycięte katalogi , i kilka innych zawiłych szczegółów na temat tego, jak -prunedziałało, ale udało mi się to z kilku przykładów.

Aby uruchomić poniższe przykłady, utwórz następujące katalogi i pliki.

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

Aby utworzyć tę strukturę:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

Teraz użyj find, aby wyszukać katalogi o nazwie aa. Tutaj nie ma problemu.

$ find . -type d -name aa
./aa

Poszukaj wszystkich katalogów innych niż aa, a my otrzymamy bieżący katalog .i ./bb, co również ma sens.

$ find . -type d ! -name aa
.
./bb

Jak dotąd tak dobrze, ale kiedy korzystamy -prune, find zwraca katalog, który przycinamy, co początkowo mnie zdezorientowało, ponieważ spodziewałem się, że zwróci wszystkie inne katalogi, a nie ten, który jest przycinany.

$ find . -type d -name aa -prune
./aa

Powód, dla którego zwraca przycinany katalog, został wyjaśniony nie w -prunesekcji stron podręcznika, jak wskazano w odpowiedzi Timo , ale w EXPRESSIONSsekcji:

Jeśli wyrażenie nie zawiera żadnych działań innych niż -prune,  -printwykonywane jest na wszystkich plikach, dla których wyrażenie jest prawdziwe.

co oznacza, że ​​ponieważ wyrażenie pasuje do aanazwy katalogu, to wyrażenie będzie miało wartość true i zostanie wydrukowane, ponieważ find niejawnie dodaje znak „ -printna końcu” całego polecenia. Nie doda to -printjednak, jeśli celowo dodasz akcję -o -printdo końca:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

Tutaj polecenie find NIE dodaje -printjuż niejawnego , więc katalog, który przycinamy ( aa), nie zostanie wydrukowany.

Wreszcie, jeśli dodamy klauzulę, która wyszukuje pliki o wzorcu nazw plików następującym file*po -o, musisz umieścić -printna końcu drugiej klauzuli w następujący sposób:

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3

Powód, dla którego to działa, jest taki sam: jeśli nie umieścisz -printw drugiej klauzuli, to ponieważ nie ma innej akcji niż -pruneakcja, find doda -printautomatycznie na KONIEC polecenia, powodując -prunewydrukowanie klauzuli przycięty katalog:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3

Ogólnie rzecz biorąc, musisz umieścić -printpolecenie w drugiej klauzuli. Jeśli umieścisz go na środku, tak jak oryginalny plakat, nie będzie działał poprawnie, ponieważ przycinane pliki zostaną wydrukowane natychmiast, a druga klauzula nie będzie miała szansy wybrać plików, które chce:

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3

Niestety, oryginalny plakat źle podał powyższe polecenie, umieszczając go -printw niewłaściwym miejscu. Mogło to zadziałać w jego konkretnym przypadku, ale nie działa w przypadku ogólnym.

Istnieją tysiące ludzi, którzy mają trudności ze zrozumieniem, jak -prunedziała. findStrona człowiek powinien być aktualizowany w celu zapobieżenia Niekończąca światową zamieszanie o tym poleceniu.

Jerry Marbas
źródło
Moja strona find-4.6.0podręcznika (Arch Linux ) mówi: „Jeśli całe wyrażenie nie zawiera żadnych działań innych niż -prune lub -print, -print jest wykonywane na wszystkich plikach, dla których całe wyrażenie jest prawdziwe”. Ale działa tak, jak to opisujesz.
x-yuri
0

ze manstrony

Aby zignorować całe drzewo katalogów, użyj opcji -prune zamiast sprawdzania każdego pliku w drzewie. Na przykład, aby pominąć katalog `src / emacs 'i wszystkie znajdujące się w nim pliki i katalogi oraz wydrukować nazwy innych znalezionych plików, wykonaj coś takiego:

find . -path ./src/emacs -prune -o -print

Być może możesz użyć:

find . -path ./.git -prune -o -print

To nie wyświetli .gitkatalogu.

aby określić nazwę pliku, możesz wykonać następujące czynności:

find . -path ./.git -prune , -name filename

Zwróć uwagę na ,przecinek operatora.

jianyongli
źródło
-1

Oto szybka i brudna alternatywa:

find | fgrep -v /.git

Po prostu nie pamiętam findzłożonej składni ...

peter.slizik
źródło