Shell Fonksiyonlarında Yerel Değişkenlerin Kapsamı


28

24.2 okuduktan sonra Yerel Değişkenler , varanahtar kelimeyle bir değişken bildirmenin , değerine yalnızca bir işlevin kıvrımlı parantezleri tarafından sınırlandırılmış kod bloğu içinde erişilebilir olduğu localanlamına geldiğini düşündüm var.

Ancak, şu örneği çalıştırdıktan sonra, ben öğrendim varda okumak, erişilebilir ve o kod bloğunda tarafından çağrılan işlevlerden yazılabilir - yani rağmen varbildirilmiş localiçin outerFunc, innerFuncyine okumak ve değerini değiştirmek yapabiliyor.

Run It 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}]"

Çıktı:

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:]

S: Bu benim kabuğumdaki bir hata mı (bash 4.3.42, Ubuntu 16.04, 64bit) ya da beklenen davranış mı?

EDIT: Çözüldü. @MarkPlotnick tarafından belirtildiği gibi, bu gerçekten beklenen bir davranış.


Beklenen davranış budur
fpmurphy

2
Son çıktı satırındaki değerin varboş olmasının garip olduğunu düşünen tek kişi ben miyim ? varküresel olarak yerleştirilmiş innerFunc, öyleyse neden betiğin sonuna kadar sadık kalmıyor?
Harold Fischer

Yanıtlar:


22

Kabuk değişkenleri dinamik bir kapsama sahiptir . Bir değişken bir fonksiyona lokal olarak bildirilirse, o fonksiyon fonksiyon geri dönene kadar bu kapsam kalır.

İki istisna vardır:

  1. ksh93'te, standart function_name () { … }sözdizimi ile bir işlev tanımlanmışsa , yerel değişkenleri dinamik izlemeye uyun. Fakat eğer bir işlev ksh sözdizimi ile tanımlanmışsa function function_name { … }, yerel değişkeni sözcüksel / statik kapsamdadır, bu nedenle bunun adı verilen diğer işlevlerde görünmez.

  2. Otomatik olarak zsh/privateyüklenebilen eklenti, statik kapsamı olan bir değişkeni bildirmek için kullanılabilecek zshbir privateanahtar kelime / yerleşik içerir.

kül, bash, pdksh ve türevleri;


Kabuktaki tüm değişkenlerin dinamik bir kapsamı var mı, yoksa bu yalnızca bildirilen değişkenler için geçerli localmi?
Harold Fischer

@HaroldFischer Tüm değişkenler dinamik kapsamlıdır. Bir typesetya declareda ya da localbildirimi ile kapsam, işlev dönene kadar geçerlidir. Böyle bir bildirim olmadan, kapsamı küreseldir.
Gilles 'SO- kötülükten vazgeçme'

6

Bu bir hata değildir, outerFunc bağlamındaki çağrı $ $ 'ın yerel kopyasını kullanır. OuterFunc'taki "yerel", küresel değişmediği anlamına gelir. OuterFunc dışındaki innerFunc işlevini çağırırsanız, global $ var değişkeni olacaktır, ancak outerFunc yerel $ var değişmez. İnnerFunc'a "local" eklerseniz, outerFunc'ın $ var değişmez - özünde, üç tanesi:

  • $ Küresel :: var
  • $ OuterFunc :: var
  • $ İnnerFunc :: var

Perl'in ad alanı biçimini kullanmak için


2

Yerel kapsamı zorlamak için bir işlev kullanabilirsiniz:

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

Örnek:

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"

Sonuç:

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]

Kaynak


2

In ilan edilmedi yerel , bu nedenle (işlev denilen edildikten sonra) görünür kapsamında kullanılabilir. function innerFunc()var='new value'

İçinde Tersine, olarak ilan edilmiştir yerel , bu nedenle (işlev denilen olsa bile) Küresel alanda bulunan değil.function outerFunc()local var='initial value'

Çünkü innerFunc()bir çocuk olarak adlandırılan outerFunc(), var lokal kapsamındadır outerFunc().

man 1 bash netleştirmeye yardımcı olabilir

yerel [seçenek] [ad [= değer] ...]

Her argüman için, ad adlı bir yerel değişken oluşturulur ve değer atanır. Seçenek, beyanda kabul edilen seçeneklerden herhangi biri olabilir. Bir işlev içinde yerel kullanıldığında, değişken isminin o işlevle ve onun çocuklarıyla sınırlı görünen bir kapsamı olmasına neden olur. ...

Tanımda beklenen zımni davranış, beyan local var='new valueedilerek elde edilebilir function innerFunc().

Diğerlerinin de belirttiği gibi, bu bash kabuğundaki bir hata değildir. Her şey olması gerektiği gibi çalışıyor.


İlk ifadeniz, kullanıcının gördükleriyle çelişiyor. Değerini yazdırma varküresel kapsamda, çağrıldıktan sonra innerFunciçinden outFunc, yazdırmıyor new value.
Kusalananda
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.