Skip to content

Latest commit

 

History

History
350 lines (255 loc) · 20.1 KB

metapříkazy.md

File metadata and controls

350 lines (255 loc) · 20.1 KB

Metapříkazy

!Štítky: {tematický okruh}{bash} !OblíbenáZaklínadla: !ÚzkýRežim: zap

Ú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.

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!

!ÚzkýRežim: vyp

Zaklínadla

Spustit jako jiný uživatel/skupina

# jako superuživatel
sudo {příkaz a parametry}

# jako uživatel
sudo -u {uzivatel} [-g {skupina}] {příkaz a parametry}

# jako skupina (alternativy)
sudo -g {skupina} {příkaz a parametry}
sg {skupina} {"příkaz s parametry"}

# jako uživatel/skupina (jen pro superuživatele)
// 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é.
sudo runuser -u {uzivatel} [-g {skupina}] {"příkaz s parametry"}
sudo runuser -g {skupina} {"příkaz s parametry"}

Interakce s interpretem

# spustit proces místo aktuálního interpretu
// 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).
exec [-c] {příkaz a parametry} [přesměrování]

# interpretovat text a vykonat jako příkazovou řádku ve stávající instanci interpretu
eval {"příkaz s parametry"}

# interpretovat a vykonat interpretem „sh
[sudo] sh -c {"příkaz s parametry"}

# interpretovat a vykonat interpretem „bash
[sudo] bash -c {"příkaz s parametry"}

# interpretovat příkaz, ale nevykonat ho
// 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).
true {příkaz a parametry}

Vykonat příkazy hromadně

# sestavit parametry příkazu ze záznamů ze vstupu, vykonat po dávkách
// 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.
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í)
// 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 „{}“).
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"

Spustit jinak...

# pokud příkaz poběží ještě po N sekundách, poslat mu signál (obecně/příklady použití)
// 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í.
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í
env [-u {promenna_k_odebrani}]... [{promenna_k_nastaveni}={hodnota}]... {příkaz a parametry}

# v jiném adresáři
env [-C {nový/aktuální/adresář}] {příkaz a parametry}

# s vypnutým účinkem operace „sync“ (obecně/příklad)
// 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í.
eatmydata {příkaz a parametry}
sudo eatmydata apt-get dist-upgrade

# s nižší/vyšší prioritou
// 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.
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í
// 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.
nocache {příkaz a parametry}

# jako démona (obecně/příklad)
// 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.
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)
env -i {příkaz a parametry}
env -i printenv

# s nebufferovaným standardním vstupem a výstupem
// 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“.
stdbuf -i 0 -o 0 {příkaz a parametry}

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í
[{promenna_k_nastaveni}={hodnota}]... {příkaz a parametry}

# změřit čas běhu příkazu
// 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.
time [-p] {příkaz a parametry} [| {další příkaz a parametry}]...

# příkaz vykonat, ale neuložit do historie
// 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).
{příkaz a parametry}

# logicky obrátit hodnotu ukládanou do $?
// 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 $?
! {příkaz a parametry} [| {další příkaz a parametry}]...

# příklad kombinace všech pseudometapříkazů
␣time ! ! LC_ALL=C mojepromenna=0 ls

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
watch -px[t][d] [-n {interval-v-sekundách}] {příkaz a parametry}

# mezi spuštěními příkazu dělat pauzu
watch -x[t][d] [-n {pauza-v-sekundách}] {příkaz a parametry}

Virtualizace vlastnictví a módu

# spustit příkaz v prostředí virtualizovaného vlastnictví a módu souborů
// Viz podsekci „Příkaz fakeroot“.
fakeroot [-u] [-i {perzistentní-soubor}] [-s {perzistentní-soubor}] {příkaz a parametry}

Ostatní metapříkazy

# spustit jedině vestavěný nebo externí příkaz (ne funkci či alias)(obecně/příklad použití)
// 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.
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
trap {"příkaz s parametry"} {signál}...

# spustit příkaz v jiné instalaci linuxu (zatím nezkoušeno)
// Správné použití tohoto příkazu je náročné na znalosti, viz sekci „Příkaz chroot“.
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)
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
builtin {příkaz a parametry}

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

!ÚzkýRežim: zap

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ší.)

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á:

!KompaktníSeznam:

  • 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:

!KompaktníSeznam:

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

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).

Další zdroje informací

Zákulisí kapitoly

V této verzi kapitoly chybí:

!KompaktníSeznam:

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

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

!KompaktníSeznam:

  • 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ů.

!ÚzkýRežim: vyp