我调用了以下脚本,.bash_functions.test
该脚本已由我的.bash_functions
脚本获取:
# vim: set syn=sh noet:
mp4Options_BIS="-movflags +frag_keyframe"
declare -A audioExtension=( [libspeex]=spx [speex]=spx [opus]=opus [vorbis]=ogg [aac]=m4a [mp3]=mp3 [mp2]=mp2 [ac3]=ac3 [wmav2]=wma [pcm_dvd]=wav [pcm_s16le]=wav )
function test1 {
echo "=> mp4Options_BIS = $mp4Options_BIS"
echo "=> audioExtension = ${audioExtension[*]}"
}
当我运行该test1
函数时,我看到以下内容:
=> mp4Options_BIS = -movflags +frag_keyframe
=> audioExtension =
最后,当我再次获取脚本并重新运行该test1
函数时,我看到了以下内容:
=> mp4Options_BIS = -movflags +frag_keyframe
=> audioExtension = ac3 wma opus mp3 wav mp2 wav spx m4a spx ogg
事实上,我Source
在第一个源调用以及source
内置函数和第二个源调用中使用了我的函数:
$ grep -r .bash_functions.test
.bash_functions:source $initDir/.bash_functions.test
$ type Source
Source is a function
Source ()
{
test "$debug" -gt 0 && time source "$@" && echo || source "$@"
}
发生的事情是这样的:
$ Source .initBash/.bash_functions.test
$ test1
=> mp4Options_BIS = -movflags +frag_keyframe
=> audioExtension =
$ source .initBash/.bash_functions.test
$ test1
=> mp4Options_BIS = -movflags +frag_keyframe
=> audioExtension = ac3 wma opus mp3 wav mp2 wav spx m4a spx ogg
为什么它会这样工作?
答案1
declare
/ typeset
without-g
除了设置类型之外还声明当前作用域中的变量。
在这里,因为declare -A audioExtension=(...)
最终在Source
函数内运行,所以导致audioExtension
变量被声明为该函数的本地变量,因此一旦Source
返回,其定义就会丢失。
您可以将其更改为typeset -Ag audioExtension=(...)
始终在全局范围内声明变量(它与 zsh/mksh/yash 不同,后者typeset -g
仅阻止变量成为本地变量(仅更新类型/属性和值);当您的Source
函数从另一个函数本身调用;参见bash 与 zsh:范围界定和 `typeset -g`了解详情)。
如果您使用ksh93
而不是bash
(这是 shellbash
借用了关联数组语法),您可以将您的Source
函数定义为:
Source() {
...
}
与以下相反:
function Source {
...
}
在 ksh93 中,使用 Bourne 风格func() cmd
语法定义的函数没有本地作用域,而function func {
具有本地作用域静止的本地范围(那里,只有一全球范围和一本地每个函数作用域,而不是本地作用域的堆栈)。
在bash
(以及其他具有本地作用域的 shell)中,没有类似的方法可以让函数不引入新的作用域。您可以使用alias
类似的替代:
shopt -s expand_aliases
if [ "$debug" -gt 0 ]; then
alias Source='time source'
else
alias Source=source
fi
(请注意,别名在代码被扩展时被扩展读,当时还没有被处决)。
与您的函数方法相比,它会在功能上产生差异:
Source ./myfile | other-cmd
我们将对两者进行计时source myfile
,并且other-cmd
随着它扩展到time source ./myfile | other-cmd
while 在函数方法中,我们只会通过计时source ./myfile
。
使用source=(time source); "${source[@]}" /some/file
不起作用(它将调用time
独立实用程序而不是bash
time 关键字)。