GNU/Linux >> Znalost Linux >  >> Linux

Opravdu vkládají závorky příkaz do podslupky?

Z toho, co jsem četl, uvedení příkazu do závorek by jej mělo spustit v podshell, podobně jako spuštění skriptu. Pokud je to pravda, jak vidí proměnnou x, když x není exportováno?

x=1

Spuštění (echo $x) na příkazovém řádku se zobrazí 1

Spuštění echo $x ve skriptu nevede k ničemu, jak se očekávalo

Přijatá odpověď:

Subshell začíná jako téměř identická kopie původního procesu shellu. Pod kapotou shell volá fork systémové volání, které vytvoří nový proces, jehož kód a paměť jsou kopiemi. Když je vytvořen podshell, existuje jen velmi málo rozdílů mezi ním a jeho rodičem. Zejména mají stejné proměnné. Dokonce i $$ speciální proměnná zachovává stejnou hodnotu v podskořápkách:je to ID procesu původního shellu. Podobně $PPID je PID rodiče původního shellu.

Několik shellů změní několik proměnných v subshell. Bash nastaví BASHPID na PID procesu shellu, který se mění v podslupkách. Bash, zsh a mksh uspořádají $RANDOM získat různé hodnoty v nadřazeném a v podslupce. Ale kromě vestavěných speciálních případů, jako jsou tyto, mají všechny proměnné stejnou hodnotu v subshell jako v původním shellu, stejný stav exportu, stejný stav pouze pro čtení atd. Všechny definice funkcí, definice aliasů, možnosti shellu a ostatní nastavení se také dědí.

Subshell vytvořený (…) má stejné deskriptory souborů jako jeho tvůrce. Některé další prostředky pro vytváření podshellů upravují některé deskriptory souborů před spuštěním uživatelského kódu; například levá strana potrubí vede v podslupce se standardním výstupem připojeným k potrubí. Subshell také začíná se stejným aktuálním adresářem, stejnou maskou signálu atd. Jednou z mála výjimek je, že subshell nedědí vlastní pasti:ignorované signály (trap '' SIGNAL ) zůstávají v subshell ignorovány, ale ostatní pasti (trap CODE SIGNÁL ) se obnoví na výchozí akci.

Subshell se tedy liší od provádění skriptu. Skript je samostatný program. Tento samostatný program může být shodou okolností také skriptem, který je spouštěn stejným interpretem jako nadřazený, ale tato shoda nedává samostatnému programu žádnou zvláštní viditelnost interních dat nadřízeného. Neexportované proměnné jsou interní data, takže když je interpret pro podřízený skript shellu spuštěn, tyto proměnné nevidí. Exportované proměnné, tj. proměnné prostředí, jsou přenášeny do prováděných programů.

Tedy:

x=1
(echo $x)

vytiskne 1 protože subshell je replikací shellu, který jej vytvořil.

x=1
sh -c 'echo $x'

náhodou spouští shell jako podřízený proces shellu, ale x na druhém řádku již nemá žádné spojení s x na druhém řádku než v

x=1
perl -le 'print $x'

nebo

x=1
python -c 'print x'

Výjimkou je ksh93 shell, kde je optimalizováno rozvětvení a většina jeho vedlejších účinků je emulována.
Sémanticky jsou to kopie. Z hlediska implementace probíhá spousta sdílení.
U pravé strany to závisí na shellu.
Pokud to otestujete, všimněte si, že věci jako $(trap) může nahlásit pasti původního pláště. Všimněte si také, že mnoho granátů má chyby v rohových pouzdrech zahrnujících pasti. Například ninjalj poznamenává, že od bash 4.3 bash -x -c 'trap "echo ERR at $BASH_SUBSHELL $BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )' spustí ERR past z vnořené podskořápky v případě „dvě podskořápky“, ale ne ERR past z mezilehlého podslupky — set -E volba by měla šířit ERR past na všechny podskořápky, ale prostřední podskořápka je optimalizována pryč, a tak tam není ke spuštění ERR past.

Související:Linux – Proč nefunguje setuid?
Linux
  1. Zvládněte příkaz Linux ls

  2. Jaký je rozdíl mezi získáním výstupu příkazu pomocí `command` a $(command) v Shell?

  3. Jsou proměnné mimo prostředí předány do podslupky vyvolány substitucí příkazů?

  1. Přizpůsobení Bash Shell:Tučné/barva Příkaz?

  2. Jak jsou závorky interpretovány na příkazovém řádku?

  3. Použití příkazu passwd ze skriptu shellu

  1. Aliasy příkazového řádku v prostředí Linux

  2. Jak spustit příkaz Vim z shellu?

  3. Skrýt výstup příkazu shellu pouze při úspěchu?