eval vs pipe through bash (Svenska)

Vad är skillnaden mellan att använda:

eval "echo "foo"" 

och

echo "echo "foo"" | bash 

finns det något?

Kommentarer

  • Här ' är en annan variant med något annorlunda beteende när det gäller exekveringsmiljöer: ( eval 'echo "foo"' )

Svar

Kort svar

Kommandot som körs av eval körs i det aktuella skalet och kommandot som skickas till bash körs i ett underskal, t.ex.:

> echo "x=42" | bash; echo $x > eval "x=42"; echo $x 42 

Längre svar

I kommentarerna gjordes påståendet att i nyare versioner av bash (> = 4.2) kan det första kommandot också ha samma effekt. Detta verkar dock inte vara fallet.

Det finns faktiskt ett par faktorer som gör att det pipade kommandot inte körs i den aktuella sessionen: röret och bash kommando.

För det mesta körs piped kommandon i subshells. Bash Manual ( Avsnitt 3.2.2: Rörledningar ) har följande att säga:

Varje kommando i en pipeline körs i sin egen subshell (se Command Execution Environment ).

Som påpekats i kommentarerna kan detta beteende ändras via alternativet lastpipe. Bash-manualen ( Avsnitt 4.3.2: Shopt Builtin ) har följande att säga om lastpipe -alternativet:

lastpipe

Om inställt och jobbkontroll inte är aktivt kör skalet det sista kommandot för en pipeline som inte körs i bakgrund i den aktuella skalmiljön.

Vi kan verifiera att så är fallet enligt följande.

Aktivera först lastpipe:

> shopt -s lastpipe 

Inaktivera sedan jobbkontroll:

> set +m 

Kör nu ett kommando som ställer in en variabel inifrån ett rör:

> unset x > echo x=42 | while IFS= read -r line; do eval "${line}"; done; > echo $x 42 

Observera att vi använder while loop och read kommando som en lösning eftersom kommandot eval inte kan läsa inmatningen från stdin (kan därför inte få sin input från ett rör).

Detta exempel visar att det högsta kommandot i röret faktiskt kan , köras i det aktuella skalet. Detta påverkar dock inte vårt ursprungliga exempel. Även med lastpipe aktiverat och jobbkontroll inaktiverat får vi fortfarande följande resultat när vi rör till bash:

> echo "x=42" | bash; echo $x > 

Detta beror på att kommandot bash själv utför sin inmatning i en subshell.

Kommentarer

  • det är en bra observation, visste ' inte det, men ja jag antar att ' s hur rör fungerar
  • Bara nyfiken, vad är anledningen till att du inte accepterade svaret?
  • För bash 4.2+ när du kör ett skript (eller mer exakt när jobbkontroll är avstängd) och shopt lastpipe är inställt och rörledningen har ingen bakgrund, den kör den högra änden av röret i ' topp ' skal inte en subshell. Se unix.stackexchange.com/questions/9954/… och unix.stackexchange.com/questions/136206/readarray-or-pipe-issue
  • @ dave_thompson_085 Kommandot bash kan köras i det övre skalet beroende på alternativ, men x=42 kommer säkert att köras i något som rimligen kan kallas en subshell.
  • @AlexanderMills Egentligen är röret inte ' t enda problemet. Kommandot bash kommer att utföra dess ingång i en subshell oavsett om ett rör är inblandat eller inte. Se uppdateringen av min lösning för mer information.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *