znajdź -exec + vs znajdź | xargs: który wybrać?

32

Rozumiem, że -execmożna wybrać +opcję naśladowania zachowania xargs. Czy jest jakaś sytuacja, w której wolisz jedną formę od drugiej?

Osobiście wolę pierwszą formę, choćby po to, by uniknąć używania rury. Myślę, że z pewnością programiści findmusieli dokonać odpowiednich optymalizacji. Mam rację?

rahmu
źródło

Odpowiedzi:

21

Możesz połączyć łańcuchowo połączenia, aby znaleźć (raz, kiedy dowiesz się, że jest to możliwe, co może być dzisiaj). Jest to oczywiście możliwe tylko tak długo, jak długo będziesz w znalezieniu. Gdy potokujesz do xargs, jest on poza zasięgiem.

Mały przykład, dwa pliki a.lst i b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Żadna sztuczka tutaj - po prostu fakt, że oba zawierają „fuddel”, ale tylko jeden zawiera „fiddel”.

Załóżmy, że o tym nie wiedzieliśmy. Szukamy pliku, który spełnia 2 warunki:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Cóż, być może znasz składnię grep lub innego programu, aby przekazać oba ciągi jako warunek, ale nie o to chodzi. Można tutaj użyć każdego programu, który może zwrócić wartość true lub false, podając plik jako argument - grep był tylko popularnym przykładem.

I pamiętaj, że możesz znaleźć find -exec za pomocą innych poleceń find, takich jak -ls lub -delete lub coś podobnego. Zauważ, że usunięcie nie tylko robi rm (usuwa pliki), ale także rmdir (usuwa katalogi).

Taki łańcuch jest odczytywany jako kombinacja ORAZ, o ile nie określono inaczej (mianowicie -orprzełącznikiem (i parenami (które wymagają maskowania))).

Więc nie opuszczasz łańcucha wyszukiwania, co jest przydatne. Nie widzę żadnej korzyści z używania -xargs, ponieważ musisz uważać na przekazywanie plików, co jest czymś, czego nie trzeba robić - automatycznie obsługuje przekazywanie każdego pliku jako pojedynczego argumentu.

Jeśli uważasz, że potrzebujesz maskowania dla znalezionych aparatów ortodontycznych {} , odwiedź moje pytanie, które wymaga dowodów. Moje twierdzenie brzmi: nie.

nieznany użytkownik
źródło
3
Ten post otworzył mi oczy na nowy sposób korzystania find. Wielkie dzięki!
rahmu
1
„Nie widzę żadnej korzyści z używania -xargs”. Jak to -execzrobić xargs -P4, aby trzy z czterech rdzeni nie pozostawały bezczynne?
Damian Yerrick
1
@DamianYerrick: Zakończ polecenie -exec nie w „;” ale ze znakiem + (/ plus).
użytkownik nieznany
25

Bezpieczne przesyłanie nazw plików do xargswymaga, abyś findobsługiwał tę -print0opcję i abyś xargsmiał odpowiednią opcję jej odczytania ( --nulllub -0). W przeciwnym razie nazwy plików z niedrukowalnymi znakami lub ukośnikami odwrotnymi lub cudzysłowami lub białymi znakami w nazwie mogą powodować nieoczekiwane zachowanie. Z drugiej strony find -exec {} +jest w specyfikacji POSIXfind , więc jest przenośny i jest tak bezpieczny, jak find -print0 | xargs -0i zdecydowanie bezpieczniejszy niż find | xargs. Polecam nigdy niefind | xargs obejść się bez -print0.

jw013
źródło
6
Godnym uwagi wyjątkiem od przenośności find … -exec … {} +jest OpenBSD, który nabył tę funkcję dopiero w wersji 5.1 wydanej w 2012 roku. Wszystkie BSD mają już -print0od kilku lat, nawet OpenBSD (choć przez pewien czas opierała się tej funkcji). Z drugiej strony Solaris trzyma się funkcji POSIX, więc dostajesz -exec +i nie -print0.
Gilles 'SO - przestań być zły'
-print0jest bólem i chociaż można argumentować xargs --delimiter "\n", że nie jest równoważny, nigdy nie użyłem tego pierwszego po odkryciu drugiego.
Sridhar Sarnobat
3
Nie rozumiem, jak -0to jest bardziej niż ból --delimiter "\n".
jw013
2
Oprócz tego -0GNU xargsmusi -runikać uruchamiania polecenia, jeśli nie ma danych wejściowych.
Stéphane Chazelas,
2
Innym problemem | xargs -r0 cmdjest to, że cmdma to wpływ na standardowe xargs/dev/null
wejście
10

Jeśli używasz -exec ... ;formularza (pamiętaj, aby uciec do średnika), uruchamiasz polecenie raz na nazwę pliku. Jeśli używasz -print0 | xargs -0, uruchamiasz wiele poleceń na nazwę pliku. Zdecydowanie powinieneś użyć -exec +formularza, który umieszcza wiele plików w jednym wierszu poleceń i jest znacznie szybszy, gdy zaangażowana jest duża liczba plików.

Dużym plusem używania xargsjest możliwość uruchamiania wielu poleceń jednocześnie xargs -P. W systemach wielordzeniowych może to zapewnić ogromne oszczędności czasu.

Alexios
źródło
6
Miałeś na myśli -Pzamiast -p. Pamiętaj xargs -P, że nie ma go w standardzie POSIX, ale find -exec {} +jest, co jest ważne, jeśli zamierzasz być przenośny.
jw013
@Alexios Nie musisz uciekać od znaku plus, ponieważ nie ma on specjalnego znaczenia dla powłoki: find /tmp/ -exec ls "{}" +działa dobrze.
Daniel Kullmann
1
Oczywiście Corrent. Tak długo uciekałem po wszystkim -exec(jestem masochistą, nawet nie używam cudzysłowów do ucieczki {}, zawsze piszę \{\}; nie pytaj), wszystko wygląda na to, że trzeba teraz uciec.
Alexios
1
@Alexios: Jeśli znajdziesz przykład (poza byciem masochistą), w którym przydatne jest maskowanie aparatu ortodontycznego, podaj go jako odpowiedź na moje pytanie tutaj - afaik ta podpowiedź jest nieaktualna i tylko relikt na stronie podręcznika. Nigdy nie widziałem przykładu, w którym find /tmp/ -exec ls {} +nie działałoby.
użytkownik nieznany
1
Dla mnie jest to pamięć mięśni utworzona w czasach SunOS 4. Ponieważ robię to od lat, zupełnie nie zauważyłem, kiedy bashzacząłem przyjmować aparat ortodontyczny dosłownie. Jestem prawie pewien, że przynajmniej jedna ze starych pocisków, którą użyłem, rzuciła syczące ataki, jeśli aparat nie uciekł.
Alexios
8

Jeśli chodzi o wydajność, pomyślałem, że -exec … +byłoby to po prostu lepsze, ponieważ jest to pojedyncze narzędzie, które wykonuje całą pracę, ale część dokumentacji GNU findutil mówi, -exec … +że w niektórych przypadkach może być mniej wydajna:

[Znajdź za pomocą -exec … +] może być mniej wydajne niż niektóre zastosowania xargs; na przykład xargspozwala budować nowe wiersze poleceń, podczas gdy poprzednie polecenie jest wciąż wykonywane, i pozwala określić liczbę poleceń, które będą uruchamiane równolegle. Jednak find ... -exec ... +konstrukcja ma tę zaletę szerokiego przenośności. Findutils GNU nie wspierały ' -exec ... +' aż do wersji 4.2.12 [styczeń 2005] ; jednym z powodów jest to, że -print0w każdym przypadku miał już działanie „ ”.

Nie byłem do końca pewien, co to znaczy, więc zapytałem na czacie, gdzie derobert wyjaśnił to jako:

findprawdopodobnie może kontynuować wyszukiwanie kolejnej partii plików podczas -exec … +działania, ale tak nie jest.
find … | xargs …robi, ponieważ wtedy znalezienie jest innym procesem i trwa do momentu zapełnienia bufora potoku

(Formatowanie przeze mnie.)

Więc to jest to. Ale jeśli wydajność naprawdę ma znaczenie, musisz przeprowadzić realistyczne testy porównawcze, a nawet zadać sobie pytanie, czy w takich przypadkach chcesz użyć powłoki.

Tutaj, na tej stronie, myślę, że lepiej doradzać ludziom korzystanie z -exec … +formularza, gdy tylko jest to możliwe, ponieważ tylko dlatego, że jest prostszy i z powodów wymienionych w innych odpowiedziach tutaj (np. Radzenie sobie z dziwnymi nazwami plików bez konieczności długiego myślenia).

phk
źródło