Jaký je rozdíl mezi použitím:
eval "echo "foo""
a
echo "echo "foo"" | bash
existují?
Komentáře
odpověď
krátká odpověď
Příkaz spuštěný eval
se provádí v aktuálním prostředí a příkaz předaný do bash
se provádí v dílčím prostředí, např .:
> echo "x=42" | bash; echo $x > eval "x=42"; echo $x 42
Delší odpověď
V komentářích bylo vzneseno tvrzení, že v novějších verzích bash
(> = 4,2) první příkaz může mít také stejný účinek. Zdá se však, že tomu tak není.
Ve skutečnosti existuje několik faktorů, které způsobují, že se příkaz piped v aktuální relaci nespustí: kanál a bash
příkaz.
Piped příkazy se většinou spouštějí v dílčích skořápkách. Manuál Bash ( Oddíl 3.2.2: Potrubí ) má toto:
Každý příkaz v kanálu se provádí ve svém vlastním subshellu (viz Prostředí pro provádění příkazů ).
Jak bylo uvedeno v komentářích, toto chování lze upravit pomocí možnosti lastpipe
. Manuál Bash ( Oddíl 4.3.2: Sestavený obchod ) má o možnosti lastpipe
říci toto:
lastpipe
Pokud je nastaveno a řízení úloh není aktivní, prostředí spustí poslední příkaz potrubí, které se v pozadí v aktuálním prostředí prostředí.
Můžeme ověřit, že tomu tak je, následujícím způsobem.
Nejprve povolte lastpipe
:
> shopt -s lastpipe
Poté deaktivujte řízení úloh:
> set +m
Nyní spusťte příkaz, který nastaví proměnnou z potrubí:
> unset x > echo x=42 | while IFS= read -r line; do eval "${line}"; done; > echo $x 42
Všimněte si, že používáme while
loop a read
příkaz jako řešení, protože příkaz eval
nemůže číst jeho vstup ze stdin (tedy nemůže získat jeho vstup z potrubí).
Tento příklad ukazuje, že příkaz zcela vpravo ve kanálu může ve skutečnosti být , být provedeny v aktuálním prostředí. To však ve skutečnosti neovlivní náš původní příklad. I když je lastpipe
povoleno a zakázáno řízení úloh, při piping na bash
stále máme následující výsledek:
> echo "x=42" | bash; echo $x >
Důvodem je, že samotný příkaz bash
provádí svůj vstup v subshellu.
Komentáře
- to je dobrý postřeh, neuvědomil jsem si to ', ale myslím, že ' Jak fungují roury
- Jen jsem zvědavý, jaký je důvod, proč jste odpověď nepřijali?
- Pro bash 4.2+ při spuštění skriptu (nebo přesněji, když je jobcontrol vypnutý) a shopt
lastpipe
je nastaven a potrubí není na pozadí, vede pravý konec kanálu v ' nahoru ' shell není subshell. Viz unix.stackexchange.com/questions/9954/… a unix.stackexchange.com/questions/136206/readarray-or-pipe-issue - @ dave_thompson_085 Příkaz
bash
lze spustit v horní shell v závislosti na možnostech, alex=42
bude jistě spuštěn v něčem, co lze rozumně nazvat subshell. - @AlexanderMills Ve skutečnosti potrubí není ' jediný problém. Příkaz
bash
provede svůj vstup v subshell bez ohledu na to, zda se jedná o rouru. Další podrobnosti najdete v aktualizaci mého řešení.
( eval 'echo "foo"' )