Scopul variabilelor locale în funcțiile Shell

După citirea 24.2. Variabile locale , am crezut că declararea unei variabile var cu cuvântul cheie local înseamnă că var „Valoarea era accesibilă numai în blocul de cod delimitat de acoladele unei funcții.

Cu toate acestea, după ce am rulat următorul exemplu, am aflat că var poate fi accesat, citit și scris și din funcțiile invocate de acel bloc de cod – adică chiar dacă var este declarat local la outerFunc, innerFunc este în continuare capabil să-l citească și să-i modifice valoarea.

Rulați-l online

#!/usr/bin/env bash function innerFunc() { var="new value" echo "innerFunc: [var:${var}]" } function outerFunc() { local var="initial value" echo "outerFunc: before innerFunc: [var:${var}]" innerFunc echo "outerFunc: after innerFunc: [var:${var}]" } echo "global: before outerFunc: [var:${var}]" outerFunc echo "global: after outerFunc: [var:${var}]" 

Ieșire:

global: before outerFunc: [var:] # as expected, `var` is not accessible outside of `outerFunc` outerFunc: before innerFunc: [var:initial value] innerFunc: [var:new value] # `innerFunc` has access to `var` ?? outerFunc: after innerFunc: [var:new value] # the modification of `var` by `innerFunc` is visible to `outerFunc` ?? global: after outerFunc: [var:] 

Q : Este o eroare în shell-ul meu (bash 4.3.42, Ubuntu 16.04, 64bit) sau este comportamentul așteptat?

EDIT: Rezolvat. După cum a menționat @MarkPlotnick, acesta este într-adevăr comportamentul așteptat.

Comentarii

  • Este comportamentul așteptat
  • Sunt eu singurul care crede că este ' ciudat faptul că pe ultima linie de ieșire valoarea var este goală? var este setat global în innerFunc, deci de ce nu ' rămâne până la sfârșit a scriptului?

Răspuns

Variabilele Shell au un domeniu dinamic . Dacă o variabilă este declarată locală pentru o funcție, domeniul respectiv rămâne până când funcția revine, inclusiv în timpul apelurilor către alte funcții.

Există două excepții:

  1. în ksh93, dacă o funcție este definită cu sintaxa standard function_name () { … }, variabilele sale locale respectă sfera dinamică. Dar dacă o funcție este definită cu sintaxa ksh function function_name { … }, atunci variabila sa locală respectă sfera lexicală / statică, deci nu sunt vizibile în alte funcții numite de aceasta.

  2. zsh/private pluginul autoîncărcabil din zsh oferă un private cuvânt cheie / încorporat care poate fi utilizat pentru a declara o variabilă cu scop static.

cenușă, bash, pdksh și derivate, bosh are doar scop dinamic.

Comentarii

  • Toate variabilele din shell au un domeniu dinamic sau se aplică acest lucru numai variabilelor declarate cu local?
  • @HaroldFischer Toate variabilele au domeniu dinamic. Cu o declarație typeset sau declare sau local, domeniul de aplicare este până când funcția revine. Fără o astfel de declarație, domeniul de aplicare este global.
  • IMHO, If a variable is declared as local to a function, that scope remains until the function returns. nu este suficient pentru a explica ce este domeniul de aplicare dinamic verus domeniul de aplicare lexical. Numai descrierea se aplică și domeniului lexical.
  • @jinbeomhong Nu, cu domeniul lexical, o variabilă dintr-o funcție nu este vizibilă în timp ce această funcție apelează o altă funcție. Am ' am adăugat o propoziție pentru a afirma acest lucru în mod explicit.
  • Afectează acest lucru și funcțiile integrate de apelare a funcțiilor? Sau încorporatele au propriul lor domeniu de aplicare?

Răspuns

Nu este „o eroare, apelul din context din externalFunc folosește acea copie locală a lui $ var. „Local” din externalFunc înseamnă că globalul nu este modificat. Dacă apelați innerFunc în afara externalFunc, atunci va exista o schimbare la $ var global, dar nu și $ var local la externalFunc. Dacă ați adăugat „local” la innerFunc, atunci $ var externalFunc nu ar putea fi modificat – în esență, ar fi 3 dintre ele:

  • $ global :: var
  • $ outerFunc :: var
  • $ innerFunc :: var

pentru a utiliza formatul spațiului de nume al Perl, un fel de.

Răspuns

În function innerFunc() var="new value" nu a fost declarat ca local , prin urmare este disponibil în domeniul vizibil (o dată funcția a fost numită).

În schimb, în function outerFunc() local var="initial value" a fost declarat ca local , prin urmare nu este disponibil în domeniul global (chiar dacă funcția a fost apelată).

Deoarece innerFunc() a fost chemat ca un copil al outerFunc(), var se încadrează în domeniul local al outerFunc().

man 1 bash poate ajuta la clarificarea

local [opțiune] [nume [= valoare] …]

Pentru fiecare argument, un local se creează numele variabilei denumite și i se atribuie valoarea. Opțiunea poate fi oricare dintre opțiunile acceptate prin declare.Când localul este utilizat într-o funcție, aceasta face ca numele variabilei să aibă un domeniu vizibil limitat la acea funcție și la copiii săi. …

Comportamentul implicit pe care îl așteptați în descriere ar putea fi realizat prin declararea local var="new value în function innerFunc().

După cum au afirmat alții, aceasta nu este o eroare în shell-ul bash. Totul funcționează așa cum ar trebui.

Comentarii

  • Prima dvs. afirmație contrazice ceea ce vede utilizatorul. Imprimarea valorii var în domeniul global, după apelarea innerFunc prin outFunc, nu not print new value.

Răspuns

Puteți utiliza un funcție pentru a forța domeniul de aplicare local:

sh_local() { eval "$(set)" command eval "\"\$@\"" } 

Exemplu:

x() { z="new value" printf "function x, z = [%s]\n" "$z" } y() { z="initial value" printf "function y before x, z = [%s]\n" "$z" sh_local x printf "function y after x, z = [%s]\n" "$z" } printf "global before y, z = [%s]\n" "$z" y printf "global after y, z = [%s]\n" "$z" 

Rezultat:

global before y, z = [] function y before x, z = [initial value] function x, z = [new value] function y after x, z = [initial value] global after y, z = [initial value] 

Sursă

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *