Czy możliwe jest zagnieżdżenie „find -exec” w innym „find -exec”?

14

Coś takiego jest tym, czego szukam, ale mój kod nie działa, bez względu na to, jak uciekam {}i+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

Po zobaczeniu tego pytania dotyczącego systemu Unix - i - Linux stwierdziłem, że poniższy kod działa, ale nie jest zagnieżdżaniem znalezionego jako takiego i podejrzewam, że jest lepszy sposób na wykonanie tego konkretnego zadania.

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

Czy istnieje jakiś sposób na zagnieżdżanie się find -execbez potrzeby wywoływania powłoki (jak wyżej), z wszystkimi jej zawrotnymi cytatami i ograniczeniami ucieczki?

Czy można to zrobić bezpośrednio za pomocą jednego polecenia find, używając kombinacji wielu jego parametrów?

Peter.O
źródło
4
Chociaż może być możliwe zrobienie tego, o co prosisz, kiedy sprawy stają się tak złożone, przełączam się na skrypty powłoki lub Perla. Twój drugi fragment kodu robi to właściwie tylko z wbudowanym skryptem powłoki. Heroiczne liniowce są zabawne, ale są trudne do zrozumienia, a zatem trudne do utrzymania. O ile nie jest to jednorazowa umowa, w której mimo to w jakiś sposób osiągasz dobre wyniki, nie widzę dobrego powodu, aby zrobić to inaczej niż wyzwanie intelektualne.
Warren Young,
1
@Warren Young: Z pewnością nie sądzę, że koncepcja jest złożona, ale zakładam, że masz na myśli, że nie ma prostego sposobu na zaradzenie find, ale jeśli findnie możesz tego zrobić, to dlaczego jest findtak czczony (?) Jako narzędzie- do użycia przy wyszukiwaniu plików? ... Kolejno stwierdziłem, że find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+działa dobrze w mojej sytuacji (odniesienie jw013 -prunedoprowadziło mnie do tego na stronie podręcznika), ale zastanawiam się, czy jest to solidna metoda (ogólnie). Nigdy tak naprawdę nie korzystałem find(w mniej niż rok z Linuksa), ponieważ locatezrobiłem prawie wszystko, czego potrzebuję, więc jest to nieznane terytorium.
Peter.O,
1
-pathTest jest dokładnie to, co miałem zamiar zaproponować. Dzięki temu powinieneś być w stanie zrobić wszystko, co chcesz (przepraszam za skojarzenie Ace Of Base;))
rozcietrzewiacz

Odpowiedzi:

8

Spróbowałbym użyć jednego znaleziska, takiego jak:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

a nawet (wcale find, po prostu globbing powłoki)

md5sum .*/*.ini

chociaż nie ma tego -type fwyboru, więc działa tylko wtedy, gdy nie masz żadnych katalogów / nie-plików kończących się na .ini. Jeśli tak, możesz użyć

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

co jednak straciłoby tę zaletę, że wymaga tylko jednego wywołania md5sum.

Edytować

Aby uzyskać ogólną i bezpieczną metodę łączenia find, możesz zrobić coś takiego

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]
jw013
źródło
Pojawia się błąd z -f(f?), A następnie kolejny błąd z -execdir… Kiedy zamieniam -execdir na -exec i / lub również zastępuję md5sum drukowaniem, nie dostaję nic…
Peter.O
Dzięki, za alternatywę ... ale bardziej findzależy mi na tym, jak to zrobić ... Nie chodzi o to, że chcę tylko rozwiązać ten przykład, szukam wglądu w sposoby find-fu .. , może jest więcej puchu niż fu w znalezieniu ... (nie wiem, bo właściwie nigdy go nie użyłem), i to jest pierwsza sytuacja, w której naprawdę chciałem go użyć (właściwie do plików graficznych) i -exec funkcja, o której tyle słyszałem, wydaje się nie być tak potężna, jak jej rep (?) nawiązuje do ... (+1 dla alternatyw, chociaż) .. ale twój findprzykład po prostu nie działa (wciąż )
Peter.O
Otrzymuję ten błąd dla findpolecenia: ... find: The relative path ~ / bin 'jest zawarty w zmiennej środowiskowej PATH, co jest niepewne w połączeniu z akcją -execdir znajdującą. Proszę usunąć ten wpis z $ PATH` .... Więc może to zadziała, ale muszę powiedzieć, że próbowałem pozbyć się tego ~ / bin już teraz ... Będę musiał wziąć więcej poważne spojrzenie na to ... nie wiem, gdzie to ustawiłem ... żadnych pomysłów, gdzie może się czaić; ~/binna mojej drodze
Peter.O
Myślę, że moc finddocenia się najlepiej w sytuacjach, których nie da się zrobić wyłącznie za pomocą globusów, ale ponieważ takie sytuacje są rzadkie, zwykle nie muszę dużo szukać.
jw013,
Okej ... to ciekawa i dobra uwaga (o używaniu globów) ...
Peter.O
2

Twój pierwotny problem nie wymaga rekurencyjnego wywoływania, ale przypuszczam, że nie o to chodziło.

Uważam, że nie można wywoływać funkcji wyszukiwania rekurencyjnie tak, jak chcesz.

Poniższe polecenie nie wywołuje rekurencyjnie find (lub zagnieżdżania, jakkolwiek się nazywa), ale czy nie możesz po prostu wziąć zestawu wyników pierwszego znalezienia i podać go drugiemu? Tak instynktownie zrobiłbym:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

Możesz także użyć xargsdo wykonania drugiego wyszukiwania.

Aktualizacja:

Chciałem dodać, że ponieważ większość narzędzi systemu UNIX pobiera kilka argumentów nazwy pliku zamiast jednego, zwykle można -execcałkowicie uniknąć :

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

Podczas zagnieżdżania tyknięć tylnych dodajesz po prostu odwrotne ukośniki \przed wewnętrznymi.

Jeśli wyobrażamy sobie, że md5sumbierze tylko jeden argument nazwy pliku, zawsze możemy zawinąć go w forpętlę:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

Zauważ, że staje się to trudniejsze, jeśli w grę -wchodzą nazwy plików / katalogów zaczynające się od lub zawierające spację. Narzędzia UNIX nie działają z nimi dobrze. W takim przypadku dodawania ./, --czy konieczna jest cytaty.

Oczywiście oryginalny przykład nie jest dobry, ponieważ moglibyśmy po prostu zrobić:

md5sum .*/*.ini
kłapnięcie
źródło
1
Dałeś dobry przegląd sytuacji, ale wszystkie przedstawione findmetody zawierają błąd, gdy plik / katalog zawiera spacje ... md5sum .*/*.iniDziała dobrze ... Zaczynam odczuwać, że * Warren Young * komentowanie rzeczy, które stają się „skomplikowane”, finddzieje się na początku gry :), ale zakładam, że findwychodzi to na jaw, gdy testy warunków są bardziej skomplikowane, ale jeśli chodzi o zagnieżdżanie - exec, całkiem dobrze porzuciłem pomysł, jak się wydaje, są prostsze sposoby, aby to zrobić .. (ale Perl nie jest „prosty” do mnie (jeszcze) ...
Peter.O
0

Przynajmniej udało mi się zagnieździć 2 polecenia znajdowania:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

Ale nie rozwiązałem problemu z wywołaniem kolejnego -exec (reż) - połączenia stamtąd.

nieznany użytkownik
źródło
Tak, to jest właśnie mój problem :)
Peter.O
Tak, ale brak zagnieżdżenia 3 nie jest tym samym, co brak zagnieżdżenia 2. :)
użytkownik nieznany