znajdź za pomocą -execdir

16

Kiedy biegnę findz -execdir, nie otrzymuję oczekiwanych rezultatów.

Na przykład:

mkdir -p a/b/c
find . -type d -execdir touch foo \;
$ tree a
a
├── b
   ├── c
   └── foo
└── foo

Katalog cnie zawiera foopliku. Jak mogę findodwiedzić i zrobić coś lokalnie w każdym katalogu?

Marcus Junius Brutus
źródło

Odpowiedzi:

18

Dla każdego pasującego pliku (tj. Każdego katalogu) findprzełącza się na katalog, który go zawiera (tj. Jego katalog nadrzędny) i wykonuje określone polecenie. Ponieważ polecenie nie używa nazwy dopasowania, nigdy nie będzie działać na wszystkie katalogi. Dla tego konkretnego drzewa katalogów robisz

(cd . && touch foo)        # because ./a matches
(cd ./a && touch foo)      # because ./a/b matches
(cd ./a/b && touch foo)    # because ./a/b/c matches

Aby utworzyć plik w każdym katalogu, możesz po prostu użyć -execzamiast -execdir, pod warunkiem, że twoja implementacja findpozwala {}wewnątrz argumentu (większość tak, a w szczególności myślę, że wszystkie):

find . -type d -exec touch {}/foo +

Aby zapewnić przenośność POSIX, należy ręcznie złożyć nazwę katalogu i nazwę pliku bazowego.

find . -type d -exec sh -c 'touch "$0/foo"' {} \;

lub (nieco szybciej)

find . -type d -exec sh -c 'for d; do touch "$d/foo"; done' _ {} +

Alternatywnie możesz użyć rekurencyjnego dopasowywania symboli wieloznacznych bash. Uwaga: (w przeciwieństwie do odpowiedniej funkcji w ksh i zsh oraz w przeciwieństwie do twojego findpolecenia) bash powtarza się pod symbolicznymi linkami do katalogów.

shopt -s globstar
for d in **/*/; do touch -- "$d/foo"; done

Rozwiązanie Zsh:

touch ./**/(e\''REPLY+=foo'\')
Gilles „SO- przestań być zły”
źródło
FYI: man bashstany pod „-c”: argumenty po łańcuchu komend są przypisywane do parametrów pozycyjnych rozpoczynających się od $ 0, jednak „for d” będzie iterował przez parametry pozycyjne rozpoczynające się od $ 1. „_” to tekst przypisany do 0 $ i nie będzie używany.
Chad Skeeters
3

Polecenie wykonuje się w każdym katalogu, który zawiera dopasowany plik. Ponieważ cnie zawiera katalogu, nie pasuje i dlatego nie zostanie tam uruchomiony.

Rozwiązaniem jest dodanie nazwy katalogu do argumentu execdir w następujący sposób:

find . -type d -execdir touch {}/foo \;
Jenny D.
źródło
2

Od man file

   -execdir command {} +
          Like  -exec,  but  the  specified  command is run from the subdirectory containing the matched file

Twój pasujący katalog c w tym bkatalogu, z którego jest uruchamiany exec. Działa tak, jak się spodziewasz, jeśli szukasz plików zamiast katalogów.

Prawdopodobnie mógłbyś osiągnąć to, co chcesz, wysyłając katalogi, xargsponieważ otrzyma to pełną listę katalogów.

Matt
źródło