xargs
xargs – polecenie uniksowych i większości uniksopodobnych systemów operacyjnych, używane do budowania i wykonywania poleceń ze standardowego wejścia. Jądro Linuxa o wersji do 2.6.23 nie może pobierać dowolnie długiej listy argumentów[1], więc zadaniem xargs jest podzielenie jej na wystarczająco małe podlisty.
Na przykład polecenie:
rm /path/*
lub
rm `find /path -type f`
może spowodować błąd i wyświetlenie komunikatu: "Argument list too long" jeżeli w /path
znajduje się zbyt wiele plików. Jednakże poniższa wersja (odpowiednik rm `find /path -type f`
) nie powinna już sprawiać kłopotów:
find /path -type f -print0 | xargs -0 rm
W tym przykładzie, find
przesyła na wejście xargs
długą listę nazw plików. Xargs
dokonuje podziału na podlisty i dopiero wtedy wywołuje polecenie rm
dla każdej z nich. To polecenie jest wydajniejsze niż gdybyśmy chcieli napisać:
find /path -type f -exec rm '{}' \;
co spowoduje wywołanie rm
dla każdego, pojedynczego pliku. Warto jednak zwrócić uwagę na to, że w nowszych wersjach find
poniższy wariant wykonuje dokładnie to samo, co wersja z użyciem xargs
:
find /path -type f -exec rm '{}' +
xargs często wykazuje się takim samym działaniem, jak backquote, lecz jest on bardziej uniwersalny i okazuje się bezpieczniejszym gdy na wejściu pojawiają się znaki białe lub specjalne. Dobrze łączyć go z poleceniami zwracającymi długie listy plików, jak chociażby find, locate, czy grep. Musimy jednak pamiętać wtedy o parametrze -0, jako że bez niego xargs nie radzi sobie najlepiej z nazwami zawierającymi ', " i spacje.
Przykłady
[edytuj | edytuj kod] find . -name "*.foo" | xargs grep bar
Równoznaczne z:
grep bar `find . -name "*.foo"`
Zauważ, że powyższa komenda korzysta z odwróconych apostrofów (`
) zamiast zwykłych ('
). Jej zadaniem jest odnalezienie wszystkich plików o rozszerzeniu .foo
, zawierających słowo bar
, położonych w bieżącym folderze oraz w jego podkatalogach. Żadne z tych poleceń nie zadziała, jeżeli wśród nazw plików znajdują się białe znaki. Możemy rozwiązać ten problem wpisując:
find . -name "*.foo" -print0 | xargs -0 grep bar
W ten sposób możemy wyodrębnić nazwy plików, rozwiązując tym samym problem z białymi znakami;
find . -name "*.foo" -print0 | xargs -0 -t -r vi
Polecenie to przypomina poprzednie, jednakowoż uruchamia ono edytor vi dla każdego z plików. Flaga -t
powoduje wypisanie komendy do strumienia stderr przed przystąpieniem do jej realizacji. -r
jest rozszerzeniem GNU informującym, że xargs
nie wykona polecenia jeżeli nie otrzyma nic na wejście.
find . -name "*.foo" -print0 | xargs -0 -I {} mv {} /tmp/trash
Powyższa komenda korzysta z -I
aby rozkazać xargs
wypełnienie {}
listą argumentów. Pamiętaj jednak, że nie wszystkie wersje xargs
wspomagają składnię {}
. W takim wypadku możesz napisać np:
find . -name "*.foo" -print0 | xargs -0 -I xxx mv xxx /tmp/trash
Powyższe polecenie wykorzystuje xxx
zamiast {}
jako znacznik listy argumentów.
find . -maxdepth 1 -type f -name "*.ogg" -print0 | xargs -0 -r cp -v -p --target-directory=/home/media
To polecenie to nic innego jak:
cp -v -p *.ogg /home/media
lecz nie zajmuje ono tak wielu zasobów, kosztem niezwracania błędu kiedy polecenie cp
otrzyma więcej plików niż może obsłużyć. Innym sposobem (w którym to sami decydujemy, gdzie umieścimy argumenty) to:
find . -maxdepth 1 -type f -name "*.ogg" -print0 | xargs -0 -IMYFILES cp MYFILES /home/media
Znak -I
w powyższej linii poleceń informuje xargs
o tym z którego słowa zastępczego chcesz skorzystać (w przeciwnym wypadku doda argumenty na końcu komendy). Oprócz tego możesz użyć atrybutu -L
w celu ograniczenia liczby argumentów. Wtedy polecenie będzie uruchamiane ponownie, aż do wyczerpania listy argumentów. Zaś użycie -L1
spowoduje uruchomienie programu tylko raz dla każdego z zadanych argumentów.
Problem separatorów
[edytuj | edytuj kod]Wiele uniksowych narzędzi jest zorientowanych liniowo. Będą one więc działać z xargs tak długo, jak linie nie zawierają '
, "
lub spacji. Część uniksowych narzędzi może użyć znaku NUL jako separatora (np. perl (wymaga -0
i \0
zamiast \n
), locate (wymaga użycia -0
), find (wymaga użycia -print0
), grep (potrzebuje -z
lub -Z
), sort (wymaga użycia -z
)). Umieszczenie -0
po xargs
rozwiązuje problem, lecz wiele innych narzędzi nie może używać znaku NUL jako separatora, np. head, tail, ls, echo, sed, tar, wc, which.
Ludzie często o tym zapominają i uznają, że xargs jest także zorientowany liniowo[2].
Poniżej zilustrowano problem separatorów:
touch 'wazny_plik'
touch 'mniej wazny_plik'
ls mniej* | xargs rm
mkdir -p '12" records'
ls | xargs rmdir
Wykonanie poleceń spowoduje usunięcie wazny_plik
i pozostawi katalog 12" records
oraz plik o nazwie mniej wazny_plik
nietknięte.
GNU Parallel jest zorientowanym liniowo odpowiednikiem Xargs, co umożliwia wykonanie powyższych zadań przy jego pomocy[3].
Przypisy
[edytuj | edytuj kod]Linki zewnętrzne
[edytuj | edytuj kod]xargs(1)
– strona podręcznika systemu Linuxxargs(1)
: konstruowanie listy argumentów i używanie narzędzia – strona podręcznika systemu FreeBSDxargs(1)
: konstruowanie listy argumentów i używanie narzędzia – strona podręcznika systemu Linuxxargs(1)
: konstruowanie listy argumentów i używanie narzędzia – strona podręcznika systemu OpenBSDxargs(1)
: konstruowanie listy argumentów i wywoływanie narzędzia – strona podręcznika systemu Linux