Jak používat příkaz xargs v systému Linux

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á ho xargs.
  • xargs předá názvy souborů příkazu wc.
  • 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 souboru directories.txt (názvy adresářů) do xargs.
  • 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 z xargs. Příkaz echo vypíše název adresáře a mkdir 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.