Linux: Kniha kouzel, vanilková příchuť 2.14 (15. července 2022)
Veškerá moc příkazové řádky/příkazového řádku přehledně, pro začátečníky i pokročilé

7. Metapříkazy

Řada 2.x vanilkové příchuti Linuxu: Knihy kouzel je od 15. července 2022 do 1. března 2025 ve stavu dlouhodobé pasivní údržby; nahlášené chyby budou opravovány, ale aktivní vývoj se již věnuje jiným projektům. Máte-li zájem pokračovat v tvorbě Linuxu: Knihy kouzel pro novější verze linuxových operačních systémů, kontaktujte autora nebo rovnou vytvořte odnož.

1. Úvod

Předmětem této kapitoly jsou příkazy jako „sudo“ či „exec“, které přijímají další příkaz i s jeho argumenty. Většina těchto příkazů najde externí program toho názvu a spustí ho v nějakým způsobem pozměněném prostředí, např. s právy superuživatele, s nižší prioritou nebo v jiném adresáři. Některé metapříkazy je možno použít i s vestavěnými příkazy Bashe.

Interpret Bash je vyvíjen v rámci projektu GNU.

2. Definice

  • Metapříkaz je příkaz, kterému lze smysluplně zadat jiný příkaz k vykonání.
  • Pseudometapříkaz je syntaktická konstrukce bashe podobná formou i účelem metapříkazům.

Kde je v zaklínadlech uvedeno příkaz a parametry, zadává se metapříkazu název vnořeného příkazu a každý jeho argument samostatně, např.:

sudo příkaz a parametry
sudo printf TEST\\n

Naopak kde je uvedeno "příkaz s parametry", zadává se celý příkazový řádek jako jeden argument (tento argument pak zpravidla bude interpretován interpretem „sh“):

sg skupina "příkaz s parametry"
sg adm 'printf TEST\\n'

Pozor na tento rozdíl!

3. Zaklínadla

3/1 Spustit jako jiný uživatel/skupina

@jako superuživatel#1
sudo příkaz a parametry
@jako uživatel#2
sudo -u uzivatel [-g skupina] příkaz a parametry
@jako skupina (alternativy)#3
sudo -g skupina příkaz a parametry
sg skupina "příkaz s parametry"
@jako uživatel/skupina (jen pro superuživatele)#4 (1)
sudo runuser -u uzivatel [-g skupina] "příkaz s parametry"
sudo runuser -g skupina "příkaz s parametry"

3/2 Interakce s interpretem

@spustit proces místo aktuálního interpretu#1 (2)
exec [-c] příkaz a parametry [přesměrování]
@interpretovat text a vykonat jako příkazovou řádku ve stávající instanci interpretu#2
eval "příkaz s parametry"
@interpretovat a vykonat interpretem „sh#3
[sudo] sh -c "příkaz s parametry"
@interpretovat a vykonat interpretem „bash#4
[sudo] bash -c "příkaz s parametry"
@interpretovat příkaz, ale nevykonat ho#5 (3)
true příkaz a parametry

3/3 Vykonat příkazy hromadně

@sestavit parametry příkazu ze záznamů ze vstupu, vykonat po dávkách#1 (4)
xargs -r0 [-a vstupní-soubor] [-n max-parametrů-na-dávku] [-P úroveň-paralelismu] příkaz a počáteční parametry
@pro každý vstupní záznam spustit příkaz a záznam dosadit do parametrů (obecně/příklad použití)#2 (5)
xargs -r0 -I '{}' [-a vstupní-soubor] [-P úroveň-paralelismu] příkaz a parametry
find . -maxdepth 1 -type f -print0 | xargs -r0 -I '{}' -P 4 ln -frsTv "{}" "{}.odkaz"

3/4 Spustit jinak...

@pokud příkaz poběží ještě po N sekundách, poslat mu signál (obecně/příklady použití)#1 (6)
timeout [-s signál] [-k trvání2] [-v] trvání1 příkaz a parametry
timeout -s KILL 5.5 yes "Ahoj, světe!"
{ timeout 1.125 yes "abc" || true; } | wc -l
@s upravenými proměnnými prostředí#2
env [-u promenna_k_odebrani] [promenna_k_nastaveni=hodnota] příkaz a parametry
@v jiném adresáři#3
env [-C nový/aktuální/adresář] příkaz a parametry
@s vypnutým účinkem operace „sync“ (obecně/příklad)#4 (7)
eatmydata příkaz a parametry
sudo eatmydata apt-get dist-upgrade
@s nižší/vyšší prioritou#5 (8)
nice -n číslo 0 až 19 příkaz a parametry
sudo nice -n číslo -1 až -20 příkaz a parametry
@s potlačením kešování#6 (9)
nocache příkaz a parametry
@jako démona (obecně/příklad)#7 (10)
nohup příkaz a parametry <vstup >kam/směřovat/výstup 2gt;kam/směřovat/chybový/výstup
nohup sort <můj-soubor.txt >seřazený-soubor.txt 2>/dev/null
@s prázdným prostředím (obecně/příklad)#8
env -i příkaz a parametry
env -i printenv
@s nebufferovaným standardním vstupem a výstupem#9 (11)
stdbuf -i 0 -o 0 příkaz a parametry

3/5 Pseudometapříkazy

Pozor na pořadí: Jsou-li pseudometapříkazy použity spolu s dalšími metapříkazy, musejí být jako první! Navíc je u nich nutno dodržet toto pořadí: „ “, „time“, „!“ (může být i víckrát), „=“ (proměnné prostředí, může být i víckrát).

Zvláštnosti: Příkaz „ “ (mezera) účinkuje na celý příkazový řádek, i když obsahuje více příkazů. Příkazy „time“ a „!“ účinkují na celou posloupnost příkazů spojených rourami.

@spustit s nastavením proměnných prostředí#1
[promenna_k_nastaveni=hodnota] příkaz a parametry
@změřit čas běhu příkazu#2 (12)
time [-p] příkaz a parametry [| další příkaz a parametry]
@příkaz vykonat, ale neuložit do historie#3 (13)
 příkaz a parametry
@logicky obrátit hodnotu ukládanou do $?#4 (14)
! příkaz a parametry [| další příkaz a parametry]
@příklad kombinace všech pseudometapříkazů#5
 time ! ! LC_ALL=C mojepromenna=0 ls

3/6 Sledování výstupu

Příkaz watch: d — zvýrazňovat změny oproti předchozímu běhu (užitečný parametr); t - nepřidávat záhlaví. Neuvedete-li parametr -n, výchozí interval jsou 2 sekundy. Parametr -n přijímá i desetinná čísla (minimální dovolená hodnota je „0.1“).

@spouštět příkaz v pravidelném intervalu#1
watch -px[t][d] [-n interval-v-sekundách] příkaz a parametry
@mezi spuštěními příkazu dělat pauzu#2
watch -x[t][d] [-n pauza-v-sekundách] příkaz a parametry

3/7 Virtualizace vlastnictví a módu

@spustit příkaz v prostředí virtualizovaného vlastnictví a módu souborů#1 (15)
fakeroot [-u] [-i perzistentní-soubor] [-s perzistentní-soubor] příkaz a parametry

3/8 Ostatní metapříkazy

@spustit jedině vestavěný nebo externí příkaz (ne funkci či alias)(obecně/příklad použití)#1 (16)
command příkaz a parametry
function echo { command echo "Toto je příkaz echo:" "$@"; }
@nastavit příkaz jako obsluhu signálu v aktuální instanci interpretu#2
trap "příkaz s parametry" signál
@spustit příkaz v jiné instalaci linuxu (zatím nezkoušeno)#3 (17)
cd /kořenový/adresář/instalace
[for x in dev proc sys dev/shm dev/pts; do sudo mount --bind {,.}/$x; done]
sudo ln -fsv /proc/mounts etc/mtab
sudo cp -fv -t etc /etc/hosts /etc/resolv.conf
sudo chroot . [runuser -u uzivatelske-jmeno] příkaz a parametry
@spustit příkaz v jiné instalaci linuxu (příklad, nezkoušeno)#4
mkdir /tmp/druhý
sudo mount -t ext4 -o rw,exec,suid,nodev /dev/sda3 /tmp/druhý
cd /tmp/druhý
for x in dev proc sys; do sudo mount --bind {,.}/$x; done
sudo chroot . runuser -u karel bash
@spustit jedině vestavěný příkaz#5
builtin příkaz a parametry

4. Instalace na Ubuntu

Všechny použité příkazy jsou základními součástmi Ubuntu přítomnými i v minimální instalaci; výjimkou jsou příkazy eatmydata, fakeroot a nocache, které je nutno doinstalovat:

sudo apt-get install eatmydata fakeroot nocache

5. Tipy a zkušenosti

  • Typickou začátečnickou chybou je očekávání, že „sudo“ bude účinkovat na přesměrování nebo substituované příkazy, např. „sudo echo "$(whoami)" >/root/test.txt“. V uvedeném příkazu proběhne jak příkaz „whoami“, tak přesměrování do souboru s právy aktuálního uživatele; práva superuživatele v tomto příkladu získá teprve až příkaz „echo“ (který je zrovna moc nepotřebuje).
  • Metapříkazy je možno řetězit, ale ne libovolně — záleží na tom, který příkaz je vestavěný a který externí. Třeba „sudo exec“ nefunguje vůbec a „exec sudo“ zase nezachová PID (protože původní PID obsadí proces „sudo“). Doporučuji s takovými možnostmi počítat a trochu experimentovat, než získáte dostatek znalostí a zkušeností, abyste dokázal/a posoudit, který příkaz se kterým a v jakém pořadí lze skombinovat a co to udělá.
  • Příkaz „xargs“ s parametrem „-n“ lze použít k rozdělení vstupu na n-tice a volání příkazu pro každou z nich. (Nebude-li počet vstupních záznamů beze zbytku dělitelný n, xargs sestaví poslední n-tici kratší.)

5/1 Příkaz chroot

Příkaz „chroot“ pro nově spouštěný příkaz (a všechny jeho potomky) nastaví určitý adresář VFS jako kořenový. Příkaz se pak vyhledá v tomto podstromu a nebude z něj mít přímý přístup ven (dokonce i symbolické odkazy se mu budou vyhodnocovat podle nového kořenového adresáře). Aby to fungovalo, daný adresář musí obsahovat části systému, které program potřebuje ke svému spuštění a běhu. Správné použití příkazu „chroot“ je náročné na znalosti systému, proto doporučuji ho používat opatrně a raději si nejprve přečíst příslušný článek na ArchWiki.

  • V podstromu nového kořenového adresáře musí být nainstalovaná nějaká instalace linuxu (do které se chystáte vstoupit).
  • Spouštěný příkaz se musí v této instalaci nacházet a mít tam i knihovny, které ke svému běhu potřebuje, a všechno nastavení.
  • Spouštěný příkaz se spustí jako root, přepnutý do nového kořenového adresáře.
  • Instalace, do které vstupujete, nemusí být stejná distribuce a nemusí obsahovat funkční jádro, musí však být stejné architektury (z 64bitového systému prý nelze vstoupit do 32bitové instalace a naopak).

Příkaz tedy z instalace, do které vstupujete, používá:

  • Programy, které spouští.
  • Knihovny.
  • Systémová a uživatelská nastavení (/etc).

Naopak z hostujícího operačního systému používá vše ostatní, zejména:

  • tabulku procesů (PID apod.)
  • přístup k zařízením (vyžaduje namapovaný /dev)
  • meziprocesovou komunikaci
  • systémové démony apod.

5/2 Příkaz fakeroot

Hlavním účelem prostředí „fakeroot“ je zdánlivě nastavit vlastnictví, skupinu a mód souborů při jejich ukládání do archivu, a to i v případech, kdy k jejich nastavení nemáte právo (popř. jsou na souborovém systému jen pro čtení, např. na DVD). Příkaz „fakeroot“ vytvoří v paměti tabulku, která k adresářovým položkám mapuje vlastnictví, skupinu a mód (ACL není v tomto prostředí dostupné, uživatelské datové položky jsem nezkoušel/a).

Následně „fakeroot“ pro spouštěný příkaz (a jeho potomky) přesměruje účinky operací „chmod“, „chgrp“ a „chown“; každá operace je nejprve provedena nad tabulkou v paměti a následně se ji program pokusí vykonat i ve skutečnosti (přičemž nevadí, když selže). Odpovídající operace čtení (např. příkazem „ls“, „stat“ či „getfacl“) budou uvnitř prostředí fakeroot vidět údaje z virtualizované tabulky namísto skutečných.

Nepoužijete-li parametr „-u“, vlastnictví a skupina se v tabulce inicializují u všech položek na „root“:„root“; mód se vždy inicializuje na jeho skutečnou hodnotu.

Spuštěnému příkazu se jeví, jako by měl práva superuživatele (např. „whoami“ vypíše „root“), ale ve skutečnosti je nemá (proto když např. vytvoří nový soubor, jeho vlastníkem bude přihlášený uživatel, nikoliv root), a namísto skutečného vlastnictví a módu vidí údaje z virtualizované tabulky.

Uvnitř prostředí „fakeroot“ nelze použít příkazy „setfacl“ a „fakeroot“; příkaz „getfacl“ zde nedokáže přečíst rozšířená přístupová práva (ale pravděpodobně to není záměr, takže se to v budoucích verzích může změnit).

6. Další zdroje informací

7. Zákulisí kapitoly

V této verzi kapitoly chybí:

  • pkexec
  • proot
  • ssh
  • pseudo (prý lepší náhrada za fakeroot)

Tato kapitola záměrně nepokrývá:

  • Příkazy, u kterých spouštění (resp. podmíněné spouštění či nespouštění) programu není jejich hlavní činností (např. „find“ s parametrem „-exec“).
  • Příkazové interprety, interprety programovacích jazyků a emulátory terminálu; výjimkou jsou „sh“ a „bash“.
  • Příkazy úzce svázané s konkrétním programem, který není široce používaný (např. „docker exec“).
  • Syntaktické konstrukce bashe (jako např. „&“) s výjimkou několika málo tzv. pseudometapříkazů.
1 Poznámka: „sudo“ u příkazu „runuser“ je pouze symbolické; ve skutečnosti se nezadává, protože příkaz „runuser“ spouští pouze root (resp. skripty běžící pod účtem root) a sudo by zde bylo zbytečné.
2 Nový proces získá PID aktuálního interpretu a většinu jeho kontextu. Parametr „-c“ před vykonáním náhrady smaže všechny proměnné prostředí (dokonce i HOME, PATH apod., takže to možná není moc dobrý nápad).
3 Hlavní smysl tohoto metapříkazu spočívá v situacích, kdy má interpretace příkazu očekávané vedlejší účinky (např. nastavení zvláštní proměnné $_ nebo uložení do historie příkazů v interaktivním režimu interpretu).
4 Neuvedete-li parametr „-n“, použije „xargs“ v každé dávce co nejvíc parametrů, kolik mu umožní systémové limity. Neuvedete-li parametr „-P“, výchozí hodnota je 1, což znamená, že další dávka se spustí, teprve až ta předchozí doběhne. Parametr „-a“ použijte v případě, že vykonávaný příkaz potřebuje přístup ke standardnímu výstupu.
5 Obsah vstupního záznamu bude dosazen do parametrů vnořeného příkazu za všechny výskyty podřetězce nastaveného parametrem „-I“ (obvykle „{}“).
6 Výchozí signál je SIGTERM (tedy požadavek na ukončení). Zadáte-li parametr „-k“, pak se po zaslání signálu odpočítá ještě „trvání2“ a příkaz se ukončí signálem SIGKILL. Obě trvání jsou v sekundách. Signály se zašlou i potomkům, které příkaz mezitím spustí.
7 Potlačení účinku operace „sync“ tímto příkazem závisí na určitých proměnných prostředí, proto se rozšíří do všech procesů, které tyto proměnné zdědí.
8 Zvýšení/snížení se počítá relativně vůči prioritě interpretu, ve kterém je příkaz použit, a výsledek se omezí do intervalu 19 (nejnižší možná priorita) až -20 (nejvyšší možná priorita). Takže když zadáte „nice -n 10 bash“, dostanete interpret s prioritou „10“, a když v něm zadáte „nice -n 6 bash“, nový interpret bude mít prioritu 16. Když pak v něm zadáte ještě „nice -n 9 bash“, třetí interpret bude mít prioritu 19.
9 Primárním účelem je bránit čtením z souborů na disku, aby se ukládala do keše; nevím jistě, nakolik se lze spolehnout, že toto čtení nebude přistupovat k datům již v keši uloženým.
10 Při použití příkazu „nohup“ důrazně doporučuji ručně přesměrovat standardní vstup a oba standardní výstupy mimo terminál; pokud to neuděláte, příkaz „nohup“ to udělá za vás, ale vypíše přitom rušivou zprávu „nohup: vstup ignoruji a výstup připojuji k 'nohup.out'“. Ostatní deskriptory přesměrovávat nemusíte, ale pokud některý z nich povede na terminál, který mezitím zavřete, program pravděpodobně skončí s chybou, jakmile se z něj pokusí číst či do něj zapisovat.
11 Užitečnost tohoto příkazu je velmi nízká, protože bude účinkovat jen na programy, které si nastavení bufferování svých vstupů nemění samy, a ani u nich nemusí výsledky odpovídat očekávání. Raději se podívejte do dokumentace příslušného programu, zda nepodporuje nějaký způsob zapnutí „nebufferovaného režimu“.
12 Pozor! Příkaz musí být spuštěn na popředí; pokud jeho běh přerušíte zkratkou Ctrl+Z, příkaz „time“ vypíše naměřený údaj a dál už měřit nebude.
13 Mezera musí prvním znakem příkazové řádky vůbec (tzn. před ní nesmí být žádný další příkaz ani jiný znak), a aby tento způsob potlačení ukládání do historie fungoval, musí být proměnná HISTCONTROL nastavena na hodnotu „ignorespace“ nebo „ignoreboth“ (což je ve výchozím nastavení v Ubuntu v interaktivním režimu bashe splněno).
14 Do $? se uloží 1 pro nulový návratový kód a 0 pro nenulový. Tento příkaz nemá žádný vliv na pole PIPE_STATUS (tam zůstanou původní hodnoty). Tento příkaz ovlivní zřetězení operátory „&&“ a „||“, protože tyto operátory čtou proměnnou $?
15 Viz podsekci „Příkaz fakeroot“.
16 Tento příkaz se nejčastěji používá, když určitý externí program nahradíte stejnojmennou funkcí a chcete ho pak z této funkce zavolat.
17 Správné použití tohoto příkazu je náročné na znalosti, viz sekci „Příkaz chroot“.
Líbí se vám tento projekt a chcete, aby byl ještě lepší? Můžete mi s tím pomoci. Zmiňte se o něm technicky zdatným přátelům, opravte překlepy a nahlašte nefunkční zaklínadla, aby mohla být opravena; poskytněte mi zpětnou vazbu nebo se zapojte do vývoje nových kapitol. Další informace na GitHubu v dokumentu Jak se zapojit.
[BY-SA]

Veškerý obsah této stránky (text, obrázky, zdrojový kód) je možno upravovat a šířit pod podmínkami licence Creative Commons Attribution-ShareAlike 4.0 International. Upozorňuji, že uvedená licence vyžaduje uvedení seznamu autorů, licence a zdroje a poskytnutí stejné či kompatibilní licence k provedeným změnám, jsou-li nějaké. Příslušné údaje jsou dostupné na stránce „Přehled autorů“. Šíření obsahu bez těchto údajů nebo šíření upravené verze bez poskytnutí adekvátní licence k provedeným úpravám je pravděpodobně porušení licenčních podmínek a může být postihováno. Poskytování zdrojového kódu při šíření není touto licencí vyžadováno.

Pro nové verze, další informace, aktuální zdrojový kód a možnost se zapojit do projektu „Linux: Kniha kouzel“ navštivte jeho repozitář na GitHubu.