Jak mogę zmusić xargs do wykonania polecenia dokładnie raz dla każdej podanej linii danych wejściowych? Domyślnie zachowuje się dzielenie linii i wykonywanie polecenia raz, przekazując wiele linii do każdej instancji.
Od http://en.wikipedia.org/wiki/Xargs :
find / path -type f -print0 | xargs -0 mb
W tym przykładzie find zawiera dane wejściowe xargs z długą listą nazw plików. xargs następnie dzieli tę listę na podlisty i wywołuje rm jeden raz dla każdej podlisty. Jest to bardziej wydajne niż ta funkcjonalnie równoważna wersja:
find / path -type f -exec rm '{}' \;
Wiem, że find ma flagę „exec”. Cytuję tylko przykładowy przykład z innego zasobu.
find /path -type f -delete
byłoby jeszcze bardziej wydajne :)Odpowiedzi:
Poniższe będzie działać tylko wtedy, gdy nie masz spacji w danych wejściowych:
ze strony podręcznika:
źródło
xargs -n 1
ten, który podałeś, pokazał „listę argumentów za długą”.MAX-LINES
zostanie pominięty, domyślniexargs -l
wynosi 1, więc wystarczy. Zobaczyćinfo xargs
.echo "foo bar" | xargs -n1 echo
. dlatego jeśli wstawisz coś takiego jak „ls”, nie poradzi sobie dobrze ze spacjami.-L 1
nie odpowiada na pierwotne pytanie i-n 1
czyni to tylko w jednej z możliwych interpretacji. Zobacz moją długą odpowiedź poniżej.-L 1
robi. Wydawało mi się, że OP najwyraźniej stara się uniknąć domyślnego zachowania polegającego na dzieleniu na części, a ponieważ zostało to zaakceptowane, zakładam, że miałem rację. Twoja odpowiedź dotyczy nieco innego przypadku użycia, w którym również chcesz zachować zbrylanie.Wydaje mi się, że wszystkie istniejące odpowiedzi na tej stronie są błędne, w tym ta oznaczona jako poprawna. Wynika to z tego, że pytanie jest niejednoznacznie sformułowane.
Podsumowanie: Jeśli chcesz wykonać polecenie „dokładnie raz dla każdej podanej linii wejściowej”, przekazując całą linię (bez nowej linii) do polecenia jako pojedynczy argument, jest to najlepszy sposób na to, aby to zrobić:
GNU
xargs
może, ale nie musi, mieć przydatne rozszerzenia, które pozwalają ci się pozbyćtr
, ale nie są one dostępne w OS X i innych systemach UNIX.Teraz długie wyjaśnienie…
Podczas korzystania z xargs należy wziąć pod uwagę dwa problemy:
Aby przetestować zachowanie xargs, potrzebujemy narzędzia, które pokazuje, ile razy jest wykonywane i ile argumentów. Nie wiem, czy jest do tego standardowe narzędzie, ale dość łatwo możemy to napisać w bash:
Zakładając, że zapiszesz go
show
w bieżącym katalogu i sprawisz, że będzie wykonywalny, oto jak to działa:Teraz, jeśli oryginalne pytanie naprawdę dotyczy punktu 2 powyżej (tak mi się wydaje, po kilkukrotnym przeczytaniu) i należy go przeczytać w ten sposób (zmiany pogrubioną czcionką):
wtedy odpowiedź brzmi
-n 1
.Porównajmy domyślne zachowanie xargs, które dzieli dane wejściowe wokół białych znaków i wywołuje polecenie tak mało razy, jak to możliwe:
i jego zachowanie z
-n 1
:Z drugiej strony, jeśli pierwotne pytanie dotyczyło dzielenia danych w punkcie 1. i powinno być czytane w ten sposób (wiele osób przybywających tutaj wydaje się myśleć, że tak jest, lub mylą te dwie kwestie):
wtedy odpowiedź jest bardziej subtelna.
Można by pomyśleć, że
-L 1
może to być pomocne, ale okazuje się, że nie zmienia to analizy argumentów. Wykonuje polecenie tylko raz dla każdej linii wejściowej, z tyloma argumentami, ile było w tej linii wejściowej:Nie tylko to, ale jeśli linia kończy się spacją, jest ona dodawana do następnej:
Oczywiście
-L
nie chodzi o zmianę sposobu, w jaki xargs dzieli dane wejściowe na argumenty.Jedynym argumentem, który robi to w sposób wieloplatformowy (z wyłączeniem rozszerzeń GNU), jest
-0
podział danych wejściowych na bajty NUL.Następnie jest tylko kwestia przetłumaczenia nowego wiersza na NUL za pomocą
tr
:Teraz parsowanie argumentów wygląda dobrze, w tym końcowe białe znaki.
Wreszcie, jeśli połączysz tę technikę
-n 1
, uzyskasz dokładnie jedno wykonanie polecenia w wierszu wprowadzania, niezależnie od tego, co masz, co może być jeszcze innym sposobem spojrzenia na pierwotne pytanie (być może najbardziej intuicyjne, biorąc pod uwagę tytuł):źródło
-L
wykonuje polecenie raz na linię wejściową (ale spacja na końcu linii łączy ją z kolejną linią, a linia jest nadal podzielona na argumenty zgodnie z białymi znakami); podczas gdy-n
wykonuje polecenie raz na argument wejściowy. Jeśli policzysz liczbę->
przykładów wyjściowych, będzie to liczba wykonań skryptu./show
.xargs
może, ale nie musi, mieć przydatne rozszerzenia, które pozwalają ci się pozbyć.tr
Ma takie bardzo przydatne rozszerzenie; fromxargs --help
- -d, --delimiter = CHARACTER elementy w strumieniu wejściowym są oddzielone CHARACTER, a nie spacjami; wyłącza przetwarzanie cytatów i ukośników odwrotnych oraz logiczne przetwarzanie EOF-L
.-L
nie mówi, ile razy wykonać skrypt w wierszu, mówi, ile wierszy danych wejściowych należy zużyć naraz.Jeśli chcesz uruchomić polecenie dla każdej linii (tzn. Wyniku)
find
, to po co ci toxargs
?Próbować:
find
ścieżka-type f -exec
twoje polecenie{} \;
gdzie literał
{}
zostaje zastąpiony nazwą pliku, a literał\;
jest potrzebny,find
aby wiedzieć, że niestandardowe polecenie się tam kończy.EDYTOWAĆ:
(po edycji pytania wyjaśniając, że wiesz
-exec
)Od
man xargs
:Pamiętaj, że nazwy plików kończące się spacjami spowodują problemy, jeśli użyjesz
xargs
:Więc jeśli nie zależy ci na tej
-exec
opcji, lepiej użyj-print0
i-0
:źródło
-L 1
jest prostym rozwiązaniem, ale nie działa, jeśli którykolwiek z plików zawiera spacje. Jest to kluczowa funkcja-print0
argumentu find - aby oddzielić argumenty znakiem „\ 0” zamiast białych znaków. Oto przykład:Lepszym rozwiązaniem jest
tr
konwersja znaków nowej linii na\0
znaki null ( ), a następnie użyciexargs -0
argumentu. Oto przykład:Jeśli musisz ograniczyć liczbę wywołań, możesz użyć
-n 1
argumentu, aby wykonać jedno wywołanie do programu dla każdego wejścia:Pozwala to również na filtrowanie danych wyjściowych find przed konwersją przerw w null.
źródło
-L
jest to, że nie pozwala na wiele argumentów dla każdegoxargs
wywołania polecenia.”?Kolejna alternatywa ...
źródło
Te dwa sposoby również działają i będą działać dla innych poleceń, które nie używają find!
przykładowy przypadek użycia:
usunie wszystkie pliki pyc z tego katalogu, nawet jeśli pliki pyc zawierają spacje.
źródło
to wszystko czego potrzebujesz.
źródło
Następujące polecenie znajdzie wszystkie pliki (-typ f),
/path
a następnie skopiuje je za pomocącp
do bieżącego folderu. Zwróć uwagę na użycie if,-I %
aby określić symbol zastępczy wcp
wierszu poleceń, aby argumenty mogły być umieszczone po nazwie pliku.find /path -type f -print0 | xargs -0 -I % cp % .
Testowane z xargs (GNU findutils) 4.4.0
źródło
Możesz ograniczyć liczbę wierszy lub argumentów (jeśli między argumentami są spacje), używając odpowiednio flag --max-lines lub --max-args.
źródło
Wygląda na to, że nie mam wystarczającej reputacji, aby dodać komentarz do powyższej odpowiedzi Tobii , więc dodam tę „odpowiedź”, aby pomóc tym z nas, którzy chcą eksperymentować w
xargs
ten sam sposób na platformach Windows.Oto plik wsadowy systemu Windows, który robi to samo, co szybko zakodowany skrypt Tobia „show”:
źródło
Odpowiedzi @Draemon wydają się być poprawne z „-0” nawet ze spacją w pliku.
Próbowałem polecenia xargs i okazało się, że „-0” działa idealnie z „-L”. nawet spacje są traktowane (jeśli wejście zostało zakończone zerem). Oto przykład:
Poniższe polecenie podzieli wartości null i wykona polecenie dla każdego argumentu na liście:
więc
-L1
wykona argument na każdym znaku zakończonym znakiem null, jeśli zostanie użyty z „-0”. Aby zobaczyć różnicę, spróbuj:nawet to wykona się raz:
Polecenie zostanie wykonane raz, ponieważ „-L” nie dzieli się teraz na bajt zerowy. do działania musisz podać zarówno „-0”, jak i „-L”.
źródło
W twoim przykładzie, przesyłanie danych wyjściowych polecenia find do xargs polega na tym, że standardowym zachowaniem opcji find -exec jest wykonanie polecenia raz dla każdego znalezionego pliku. Jeśli używasz find i chcesz jego standardowe zachowanie, odpowiedź jest prosta - nie używaj xargs na początek.
źródło
find
, i dlatego nie preferują tej-exec
opcji.Wykonaj ant clean-all na każdym pliku build.xml w bieżącym lub podfolderze.
źródło
ant
zainstalowany.