Wat is het verschil tussen het gebruik van:
eval "echo "foo""
en
echo "echo "foo"" | bash
is er een?
Opmerkingen
Antwoord
Kort antwoord
Het commando dat wordt uitgevoerd door eval
wordt uitgevoerd in de huidige shell en het commando dat wordt doorgesluisd naar bash
wordt uitgevoerd in een subshell, bijvoorbeeld:
> echo "x=42" | bash; echo $x > eval "x=42"; echo $x 42
Langer antwoord
In de commentaren werd beweerd dat in recentere versies van bash
(> = 4.2) het eerste commando zou ook hetzelfde effect kunnen hebben. Dit lijkt echter niet het geval te zijn.
Er zijn feitelijk een aantal factoren die ervoor zorgen dat het doorgesluisde commando niet wordt uitgevoerd in de huidige sessie: de pipe en de bash
commando.
Voor het grootste deel worden doorgesluisde commandos uitgevoerd in subshells. De Bash-handleiding ( Sectie 3.2.2: Pipelines ) heeft het volgende te zeggen:
Elk commando in een pijplijn wordt uitgevoerd in zijn eigen subshell (zie Command Execution Environment ).
Zoals aangegeven in de commentaren, kan dit gedrag worden gewijzigd via de optie lastpipe
. De Bash-handleiding ( Sectie 4.3.2: The Shopt Builtin ) heeft het volgende te zeggen over de lastpipe
optie:
lastpipe
Indien ingesteld en job control is niet actief, voert de shell het laatste commando uit van een pijplijn die niet in de achtergrond in de huidige shell-omgeving.
We kunnen als volgt verifiëren dat dit het geval is.
Schakel eerst lastpipe
:
> shopt -s lastpipe
Schakel vervolgens job-control uit:
> set +m
Voer nu een commando uit dat een variabele instelt vanuit een pipe:
> unset x > echo x=42 | while IFS= read -r line; do eval "${line}"; done; > echo $x 42
Merk op dat we de while
loop en read
commando als een tijdelijke oplossing aangezien het eval
commando zijn invoer niet kan lezen van stdin (en kan daarom zijn invoer niet krijgen van a pipe).
Dit voorbeeld laat zien dat het meest rechtse commando in de pipe dat ook kan , worden uitgevoerd in de huidige shell. Dit heeft echter geen invloed op ons oorspronkelijke voorbeeld. Zelfs met lastpipe
ingeschakeld en taakbeheer uitgeschakeld, krijgen we nog steeds het volgende resultaat wanneer we doorsluizen naar bash
:
> echo "x=42" | bash; echo $x >
Dit komt doordat het bash
commando zelf zijn invoer in een subshell uitvoert.
Opmerkingen
- dat is een goede observatie, ' realiseerde me dat niet, maar ja ik denk dat ' s hoe leidingen werken
- Gewoon nieuwsgierig, wat is de reden waarom je het antwoord niet accepteerde?
- Voor bash 4.2+ bij het draaien van een script (of meer precies wanneer jobcontrol is uitgeschakeld) en shopt
lastpipe
is ingesteld en de pijplijn heeft geen achtergrond, het voert het rechteruiteinde van de pijpleiding uit in de ' top ' shell geen subshell. Zie unix.stackexchange.com/questions/9954/… en unix.stackexchange.com/questions/136206/readarray-or-pipe-issue - @ dave_thompson_085 Het
bash
commando kan worden uitgevoerd in de bovenste shell afhankelijk van de opties, maarx=42
zal zeker worden uitgevoerd in iets dat redelijkerwijs een subshell kan worden genoemd. - @AlexanderMills Eigenlijk is de pijp niet ' t het enige probleem. Het
bash
commando zal zijn invoer in een subshell uitvoeren, ongeacht of het om een pipe gaat of niet. Zie de update van mijn oplossing voor meer details.
( eval 'echo "foo"' )