local
在匹配参数选项后一直在我的 bash 函数中使用。
----- plist -----
local fdir=${dpath:-$PWD}
pregion "${ropts[@]}"
----- 区域 -----
("-d"|"--directory")
local fdir=$2 ; shift ; shift ;;
...
# later on
: ${fdir:="${@:$#}"}
但是当我在pregion
.
: ${fdir:="${@:$#}"}
因为fdir
正在设置中plist
。
答案1
local
表示变量在该函数中可见(读/写)并在它调用的任何函数中(以及任何由那些, ETC)。您在 case 分支中使用
local
:如果未传递 -d 选项会发生什么?那么该变量就不是本地的。这就是你所看到的吗?
在没有看到更多代码的情况下,我不知道还有什么建议。
答案2
就像在bash
大多数 shell 中一样local
¶typeset
动态的范围界定。在函数中声明为本地的变量不仅对该函数是本地的/可见的。
唯一发生的事情是,在调用时local
(第一次在函数中),将创建变量的新实例,该实例会隐藏父作用域中的相应变量,并且当函数返回时,该变量将被销毁,并且该变量将被销毁。下恢复了。在包括其他函数在内的任何代码中运行的任何代码仍然可以看到该变量。
对于带有静止的作用域,您需要切换到 ksh93(并使用function f { ...; }
函数定义样式(不是f() { ...; }
Bourne 样式),或 zsh 并使用其private
内置函数。
$ ksh -c 'function f { typeset a=1; echo "f: $a"; g; }; function g { echo "g: $a"; }; a=0; f'
f: 1
g: 0
$ zsh -c 'zmodload zsh/param/private; f() { private a=1; echo "f: $a"; g; }; g() { echo "g: $a"; }; a=0; f'
f: 1
g: 0
$ bash -c 'f() { local a=1; echo "f: $a"; g; }; g() { echo "g: $a"; }; a=0; f'
f: 1
g: 1
看看 in 如何bash
g
看到$a
其父f
级的 , while in ksh93
(或zsh
在哪里f
声明了$a
私人的在调用g
) 之前,g
会看到$a
全局范围的 。
不过,在您的情况下bash
,您不想在全局范围内pregion
考虑$fdir
,因此您需要做的就是声明您的fdir
本地变量,并且在开始向其分配任何内容之前不带值:
pregion() {
local fdir # declares it unset (as long as the localvar_inherit
# option is not set).
...
("-d"|"--directory")
fdir=$2 ; shift ; shift ;;
...
# later on
: "${fdir=${@:$#}}"
...
}
另请注意,引号位于错误的位置,导致扩展受到 split+glob 的影响。另请注意,: ${fdir:="${@:$#}"}
${var:=value}
分配value
给$var
if$var
之前是空的$var
,而如果以前是您可能想要它未设置,也就是说,如果fdir=$2
上面没有运行,则语法为${var=value}
。
在这里,你还可以这样做:
pregion() {
local fdir="${@:$#}"
...
("-d"|"--directory")
fdir=$2 ; shift ; shift ;;
...
}
即无条件地将最后一个位置参数分配给$fdir
第一个,然后如果-d
传递了则覆盖它。
更一般地说,您需要在开始使用所有局部变量之前将其声明为局部变量,并在具有动态作用域的 shell 中,为您的变量选择一些命名约定。全球的变量以确保它们不会与局部变量冲突。所有大写变量都是常见的,尽管您可能需要考虑与众所周知的潜在冲突环境变量。
1 包括 ksh83 - ksh88,其中引入了带有排版的本地作用域,bash 主要模仿的 shell,以及local
引入命令的 Almquist shell(尽管在本例中工作方式不同,因为局部变量继承了变量的值和属性)父作用域;请参阅localvar_inherit
更高版本的 bash 中的选项以获得类似的行为)