find -exec cmd {} + vs | xargs

115

Który z nich jest bardziej wydajny w przypadku bardzo dużego zestawu plików i powinien być używany?

find . -exec cmd {} +

lub

find . | xargs cmd

(Załóżmy, że w nazwach plików nie ma zabawnych znaków)

dogbane
źródło
Związane z: stackoverflow.com/questions/9612090/…
Mateusz Piotrowski

Odpowiedzi:

107

Różnica prędkości będzie nieznaczna.

Ale musisz się upewnić, że:

  1. Twój skrypt nie przyjmie, że żaden plik nie będzie miał spacji, tabulacji itp. W nazwie pliku; pierwsza wersja jest bezpieczna, druga nie.

  2. Twój skrypt nie potraktuje pliku zaczynającego się od „ -” jako opcji.

Twój kod powinien więc wyglądać następująco:

find . -exec cmd -option1 -option2 -- {} +

lub

find . -print0 | xargs -0 cmd -option1 -option2 --

Pierwsza wersja jest krótsza i łatwiejsza do napisania, ponieważ można zignorować 1, ale druga wersja jest bardziej przenośna i bezpieczna, ponieważ „ -exec cmd {} +” jest stosunkowo nową opcją w GNU findutils (od 2005 roku wiele działających systemów jeszcze jej nie ma) i ostatnio było wadliwe . Również wiele osób nie wie o tym " -exec cmd {} +", jak widać na podstawie innych odpowiedzi.

Tometzky
źródło
4
-print0 jest również opcją GNU find (i GNU xargs), której brakuje w wielu systemach innych niż Linux, więc argument przenośności nie jest tak poprawny. Korzystanie tylko -print i pozostawiając -0 off xargs, jednak jest bardzo przenośny.
dannysauer
7
Chodzi o to, że bez -print0 to nie zadziała jeśli jest plik ze spacją lub tabulatorem itp. Może to być luka w zabezpieczeniach tak jakby nazwa pliku taka jak "foo -o index.html" wtedy -o zostanie potraktowana jako opcja. Spróbuj w pustym katalogu: "touch - foo \ -o \ index.html; znajdź. | Xargs cat". Otrzymasz: „cat: invalid option - 'o'”
Tometzky
2
Jego przykładem jest nazwa pliku zawierająca -. Bez -print0 find wypluje ./foo -o index.html. Więc może rozpoczęcie od - to nic wielkiego, ale wynik jest trochę zmieniony, a w systemie wielu użytkowników może zapewnić wektor ataku, jeśli twój skrypt jest czytelny dla całego świata.
bobpaul
2
Uwaga na temat czegoś, co mnie tutaj execzaskoczyło - użycie spowoduje wyświetlenie wyników w takiej postaci, w jakiej zostaną znalezione, xargsco, jak się wydaje, będzie czekało , aż cały katalog zostanie przeszukany przed zapisaniem na standardowe wyjście. Jeśli próbujesz tego na dużym katalogu i wydaje się, że xargsto nie działa, cierpliwość jest wskazana.
FarmerGedden
1
@Motivated Bez funkcji -print0find zwraca nazwy plików oddzielone znakiem nowej linii, ale nowa linia może również być częścią nazwy pliku, co czyni ją niejednoznaczną. Bajt 0 nie może, więc jest to bezpieczny separator. Tak - dodanie --do polecenia, które je obsługuje, jest dobrą praktyką, gdy nie możesz kontrolować jego argumentów, nawet jeśli nie zawsze jest to wymagane lub niebezpieczne.
Tometzky
7
find . | xargs cmd

jest bardziej efektywny (działa cmdtak kilka razy, jak to możliwe, w przeciwieństwie do tego exec, że działa cmdraz na każdy mecz). Jednak napotkasz kłopoty, jeśli nazwy plików zawierają spacje lub znaki funky.

Sugeruje się użycie:

find . -print0 | xargs -0 cmd

to będzie działać, nawet jeśli nazwy plików zawierają znaki funkowe ( -print0marki findwydrukować znakiem NUL mecze, -0marki xargsoczekiwać tego formatu).

Zapytać
źródło
28
To nie jest polecenie „find. -Exec cmd {} \;” ale „znajdź. -exec cmd {} +”. Ten ostatni nie będzie uruchamiał jednego pliku na raz.
Tometzky
2
Zwróć uwagę, że xargspodejście to jest w rzeczywistości znacznie wolniejsze, jeśli nie ma pasujących plików (lub tylko kilka) i cmdnie ma wiele do zrobienia dla każdego pliku. Na przykład, jeśli zostanie uruchomiona w pustym katalogu, xargswersja zajmie co najmniej dwa razy więcej czasu, ponieważ zamiast jednego trzeba uruchomić dwa procesy. (Tak, różnica jest zwykle niezauważalna na * nix, ale w pętli może być ważna; lub spróbuj to kiedyś w systemie Windows ...)
SamB
2

xargsWersje Modern często obsługują równoległe wykonywanie potoków.

Oczywiście może to być punkt zwrotny, jeśli chodzi o wybór między find … -exec a … | xargs

poige
źródło