Potřebujete zkombinovat několik linuxových příkazů, ale jeden z nich neumí přijímat data z roury? Příkaz xargs
vám s tím pomůže. Umožňuje vzít výstup jednoho příkazu a použít ho jako parametry pro jiný příkaz.
Každý standardní nástroj v Linuxu má tři základní datové toky. Jsou to standardní vstup (stdin
), standardní výstup (stdout
) a standardní chybový výstup (stderr
). Tyto toky pracují s textem. Vstup (stdin
) se posílá příkazu ve formě textu, odpověď (stdout
) se vypisuje jako text do terminálu a chybové zprávy (stderr
) se také zobrazují v terminálu.
Jednou z výhod Linuxu a systémů založených na Unixu je možnost přesměrovat výstup (stdout
) jednoho příkazu do vstupu (stdin
) druhého příkazu. První příkaz nezajímá, že jeho výstup nejde do terminálu a druhý příkaz se nestará, že vstup nepochází z klávesnice.
Ačkoli všechny linuxové příkazy mají tyto tři standardní datové toky, ne všechny z nich akceptují výstup (stdout
) jiného příkazu jako vstup do svého stdin
. To znamená, že do nich nemůžete poslat data pomocí roury.
Právě zde přichází na řadu xargs
. Jedná se o příkaz, který dokáže vytvářet prováděcí řetězce pomocí standardních datových toků. Díky xargs
můžeme docílit toho, že příkazy jako echo
, rm
nebo mkdir
budou přijímat standardní vstup jako argumenty.
Jak funguje příkaz xargs
Příkaz xargs
přijímá vstup z roury nebo souboru a tento vstup používá jako parametry pro příkazy, které mu určíme. Pokud mu neurčíme žádný konkrétní příkaz, standardně použije echo
. To můžeme využít pro demonstraci, jak xargs
vždy generuje jediný řádek výstupu i z víceřádkového vstupu.
Použijeme-li volbu -1
(jeden soubor na řádek) s příkazem ls
, získáme sloupec názvů souborů.
ls -1 ./*.sh
Zde jsou vypsány všechny shell skripty v aktuálním adresáři.
Jak jsme očekávali, máme jeden sloupec. Co se stane, když tento výstup spojíme s xargs
?
ls -1 ./*.sh | xargs
Výstup se objeví v terminálu jako jeden dlouhý textový řádek.
Právě tato schopnost vkládat parametry do jiných příkazů činí xargs
tak užitečným.
Využití xargs s příkazem wc
Pomocí xargs
můžeme jednoduše spočítat počet slov, znaků a řádků ve více souborech.
ls *.page | xargs wc
Co se zde děje:
ls
vypíše seznam souborů s příponou*.page
a předá hoxargs
.xargs
předá názvy souborů příkazuwc
.wc
zpracuje názvy souborů, jako by byly zadány přímo jako parametry v příkazové řádce.
Zobrazí se statistiky pro každý soubor a také celkový součet.
Interaktivní použití s xargs
Můžeme využít volbu -p
(interaktivní), díky které nás xargs
požádá o potvrzení, zda chceme pokračovat.
Pokud pomocí xargs
předáme řetězec s názvy souborů, které se mají vytvořit, příkaz touch
vytvoří požadované soubory.
echo 'one two three' | xargs -p touch
Zobrazí se příkaz, který se má provést, a xargs
čeká na naši odpověď. Musíme zadat „y“ nebo „Y“ pro potvrzení a „n“ nebo „N“ pro zrušení. Pokud jen stiskneme Enter, bere se to jako „n“. Příkaz se provede pouze, když zadáme „y“ nebo „Y“.
Zadali jsme „y“ a stiskli Enter. Pomocí ls
můžeme zkontrolovat, zda se soubory vytvořily.
ls one two three
Použití více příkazů s xargs
Díky volbě -I
(počáteční argumenty) můžeme použít s xargs
více příkazů.
Tato volba definuje „nahrazující řetězec“. Kdykoliv se v příkazové řádce objeví tento řetězec, vloží se na jeho místo hodnoty, které byly předány do xargs
.
Podíváme se na podadresáře aktuálního adresáře pomocí příkazu tree
. Volba -d
(adresář) zajistí, že tree
bude ignorovat soubory a zobrazí pouze adresáře.
tree -d
V aktuálním adresáři je jeden podadresář s názvem „images“.
V souboru „directories.txt“ máme názvy několika adresářů, které chceme vytvořit. Obsah tohoto souboru si můžeme zobrazit pomocí cat
.
cat directories.txt
Použijeme tento soubor jako vstupní data pro xargs
. Zde je příkaz, který použijeme:
cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'
Rozklad příkazu:
cat directories.txt |
: Vloží obsah souborudirectories.txt
(názvy adresářů) doxargs
.xargs -I %
: Definujeme „nahraditelný řetězec“ jako „%“.sh -c
: Spustí nový subshell.-c
říká shellu, aby četl příkazy z příkazové řádky.'echo %; mkdir %'
: Každý výskyt „%“ bude nahrazen názvy adresářů předanými zxargs
. Příkazecho
vypíše název adresáře amkdir
vytvoří adresář.
Adresáře se vypisují jeden po druhém.
Můžeme znovu použít tree
, abychom ověřili, že adresáře byly vytvořeny.
tree -d
Kopírování souborů do více umístění
S xargs
můžeme kopírovat soubory do několika umístění jedním příkazem.
Názvy dvou adresářů předáme do xargs
jako vstupní parametry. Řekneme xargs
, aby příkazu, se kterým pracuje, předával vždy jen jeden parametr. V tomto případě je tím příkazem cp
. Výsledkem je, že se příkaz cp
volá dvakrát, jednou s každým z adresářů jako parametrem. Toho docílíme díky volbě -n
(maximální počet). Tuto hodnotu nastavíme na jedna.
S příkazem cp
používáme volbu -v
(verbózní), která nám bude hlásit, co se děje.
echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page
Soubory se kopírují do dvou adresářů, jeden po druhém. cp
hlásí každou akci kopírování souboru, takže vidíme, co se děje.
Mazání souborů ve vnořených adresářích
Pokud názvy souborů obsahují mezery a jiné speciální znaky (např. znaky nového řádku), xargs
je nebude správně interpretovat. Tento problém můžeme vyřešit pomocí volby -0
(null terminátor). Díky ní bude xargs
používat znak null jako oddělovač názvů souborů.
V tomto příkladu použijeme find
. find
má vlastní volbu pro řešení mezer a speciálních znaků v názvech souborů. Je to volba -print0
(celé jméno, znak null).
find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"
Rozklad příkazu:
find . -name "*.png"
:find
bude hledat v aktuálním adresáři (.
) objekty, jejichž název odpovídá"*.png"
a jsou to soubory (-type f
).-print0
: názvy budou ukončeny znakem null, což vyřeší problémy s mezerami a speciálními znaky.xargs -0
:xargs
bude také brát názvy souborů za ukončené znakem null, takže se vyhneme problémům s mezerami a spec. znaky.rm -v -rf "{}"
:rm
bude podrobný a bude hlásit, co se děje (-v
). Bude rekurzivní (-r
), projde i vnořené podadresáře a bez ptaní odstraní soubory (-f
).{}
je nahrazeno názvem každého souboru.
Prohledají se všechny podadresáře a smažou se soubory, které odpovídají vyhledávacímu vzoru.
Odebírání vnořených adresářů
Řekněme, že chceme odstranit sadu vnořených podadresářů. tree
nám je zobrazí.
tree -d
find . -name "level_one" -type d -print0 | xargs -0 rm -v -rf "{}"
Tento příkaz používá find
k rekurzivnímu vyhledávání v aktuálním adresáři. Cílem hledání je adresář s názvem „level_one“. Názvy adresářů se předávají přes xargs
do příkazu rm
.
Jediný rozdíl mezi tímto příkazem a předchozím je, že hledáme adresáře (-type d
) s názvem „level_one“.
Název každého adresáře se vypíše po jeho odstranění. Můžeme se přesvědčit pomocí tree
:
tree -d
Všechny vnořené podadresáře byly odstraněny.
Smazání všech souborů, kromě jednoho typu
Pomocí find
, xargs
a rm
můžeme smazat všechny soubory kromě jednoho typu, který si chceme ponechat. Je to trochu neintuitivní, protože udáváme typ souboru, který chceme zachovat, a ne ty, co chceme smazat.
Volba -not
říká find
, aby vrátil názvy souborů, které neodpovídají vyhledávacímu vzoru. Opět použijeme volbu -I
(počáteční argumenty) s xargs
. Tentokrát definujeme nahrazující řetězec jako {}
. Bude se chovat stejně jako v předchozích příkladech, kde jsme použili %
.
find . -type f -not -name "*.sh" -print0 | xargs -0 -I {} rm -v {}
Můžeme to zkontrolovat pomocí ls
. V adresáři zůstaly pouze soubory, které odpovídaly vyhledávacímu vzoru *.sh
.
ls -l
Vytvoření archivu pomocí xargs
S příkazem find
můžeme vyhledat soubory a předat je přes xargs
do tar
pro vytvoření archivu.
Budeme hledat v aktuálním adresáři. Vzor hledání je *.page
, takže budeme hledat soubory .page
.
find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz
Při vytváření archivu se zobrazí výpis souborů, jak jsme očekávali.
Prostředník dat
Někdy potřebujete něco, co spojí dohromady různé prvky. xargs
překlenuje propast mezi příkazy, které umí získávat informace, a příkazy, které je nejsou schopny přímo přijmout.
Jak xargs
, tak find
mají mnoho různých voleb. Doporučujeme vám podívat se na jejich manuálové stránky, kde se o nich dozvíte víc.