eval vs. pipe through bash

Wat is het verschil tussen het gebruik van:

eval "echo "foo"" 

en

echo "echo "foo"" | bash 

is er een?

Opmerkingen

  • Hier is ' een andere variant met enigszins ander gedrag wat betreft uitvoeringsomgevingen: ( eval 'echo "foo"' )

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, maar x=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.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *