我正在写一个bash脚本set -u,我有一个空数组扩展的问题:bash似乎在扩展期间将空数组视为未设置的变量:
$ set -u
$ arr=()
$ echo "foo: '${arr[@]}'"
bash: arr[@]: unbound variable
Run Code Online (Sandbox Code Playgroud)
(declare -a arr也没帮助.)
对此的常见解决方案是使用${arr[@]-}替代,从而替换空字符串而不是("未定义")空数组.然而,这不是一个好的解决方案,因为现在你无法辨别出一个带有一个空字符串的数组和一个空数组.(@ -expansion在bash中是特殊的,它扩展"${arr[@]}"为"${arr[0]}" "${arr[1]}" …,这使它成为构建命令行的完美工具.)
$ countArgs() { echo $#; }
$ countArgs a b c
3
$ countArgs
0
$ countArgs ""
1
$ brr=("")
$ countArgs "${brr[@]}"
1
$ countArgs "${arr[@]-}"
1
$ countArgs "${arr[@]}"
bash: arr[@]: unbound variable
$ set +u
$ countArgs "${arr[@]}"
0
Run Code Online (Sandbox Code Playgroud)
那么有没有办法解决这个问题,除了检查一个数组的长度if(参见下面的代码示例),或关闭-u该短片的设置?
if [ "${#arr[@]}" = 0 ]; then
   veryLongCommandLine
else
   veryLongCommandLine "${arr[@]}"
fi
Run Code Online (Sandbox Code Playgroud)
更新:bugs由于ikegami的解释删除了标签.
ike*_*ami 74
首先,它不是一个错误.
如果已为下标指定值,则认为数组变量已设置.空字符串是有效值.
没有为下标分配值,因此未设置数组.
有一个条件,您可以使用内联来实现您想要的:使用${arr[@]+"${arr[@]}"}而不是"${arr[@]}".
$ bash --version | head -n 1
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
$ set -u
$ arr=()
$ echo "foo: '${arr[@]}'"
foo: ''
Run Code Online (Sandbox Code Playgroud)
用bash 4.2.25和4.3.11测试
dim*_*414 40
${arr[@]+"${arr[@]}"}这已经是池上回答中的建议,但在这个线程中有很多错误信息和猜测。其他模式(例如${arr[@]-}或 )在 Bash 的所有主要版本${arr[@]:0}中都不是安全的。
如下表所示,在所有现代 Bash 版本中唯一可靠的扩展是${arr[@]+"${arr[@]}"}(column +")。值得注意的是,Bash 4.2 中的其他几个扩展失败了,包括(不幸的是)较短的${arr[@]:0}习惯用法,它不仅会产生错误的结果,而且实际上失败了。如果您需要支持 4.4 之前的版本,尤其是 4.2,这是唯一可行的习惯用法。
不幸的+是,乍一看看起来相同的其他扩展确实会发出不同的行为。例如,使用:+代替+(:+"在表中) 不起作用,因为:-expansion将具有单个空元素 ( (''))的数组视为“null”,因此不会(始终)扩展为相同的结果。
引述全膨胀,而不是嵌套阵列("${arr[@]+${arr[@]}}","+在表中),我会预期是大致相当于,在4.2类似地不安全的。
您可以在此要点中查看生成此数据的代码以及 bash 的其他几个版本的结果。
小智 23
@ ikegami接受的答案是巧妙的错误!正确的咒语是${arr[@]+"${arr[@]}"}:
$ countArgs () { echo "$#"; }
$ arr=('')
$ countArgs "${arr[@]:+${arr[@]}}"
0   # WRONG
$ countArgs ${arr[@]+"${arr[@]}"}
1   # RIGHT
$ arr=()
$ countArgs ${arr[@]+"${arr[@]}"}
0   # Let's make sure it still works for the other case...
Run Code Online (Sandbox Code Playgroud)
        Jay*_*yen 14
对于那些不想复制arr [@]并且可以使用空字符串的人来说,这可能是另一种选择
echo "foo: '${arr[@]:-}'"
Run Code Online (Sandbox Code Playgroud)
去测试:
set -u
arr=()
echo a "${arr[@]:-}" b # note two spaces between a and b
for f in a "${arr[@]:-}" b; do echo $f; done # note blank line between a and b
arr=(1 2)
echo a "${arr[@]:-}" b
for f in a "${arr[@]:-}" b; do echo $f; done
Run Code Online (Sandbox Code Playgroud)
        agg*_*g3l 13
事实证明,在最近发布的(2016/09/16)bash 4.4中已经改变了阵列处理(例如在Debian stretch中可用).
$ bash --version | head -n1
bash --version | head -n1
GNU bash, version 4.4.0(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)
现在空数组扩展不会发出警告
$ set -u
$ arr=()
$ echo "${arr[@]}"
$ # everything is fine
Run Code Online (Sandbox Code Playgroud)
        @ ikegami的答案是正确的,但我认为语法"${arr[@]:+${arr[@]}}"可怕.如果你使用长数组变量名,它开始看起来比平时更快.
试试这个:
$ set -u
$ count() { echo $# ; } ; count x y z
3
$ count() { echo $# ; } ; arr=() ; count "${arr[@]}"
-bash: abc[@]: unbound variable
$ count() { echo $# ; } ; arr=() ; count "${arr[@]:0}"
0
$ count() { echo $# ; } ; arr=(x y z) ; count "${arr[@]:0}"
3
Run Code Online (Sandbox Code Playgroud)
看起来Bash数组切片运算符非常宽容.
那么为什么Bash如此难以处理数组的边缘情况呢? 叹. 我不能保证你的版本会允许滥用数组切片操作符,但它对我来说很有用.
警告:我使用GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
你的里程可能会有所不同.
小智 6
确实"有趣"的不一致.
此外,
$ set -u
$ echo $#
0
$ echo "$1"
bash: $1: unbound variable   # makes sense (I didn't set any)
$ echo "$@" | cat -e
$                            # blank line, no error
Run Code Online (Sandbox Code Playgroud)
虽然我同意当前的行为可能不是@ikegami解释的错误,IMO我们可以说错误在定义("set")本身,和/或它不一致地应用的事实.手册页中的前一段说
...
${name[@]}将名称的每个元素扩展为单独的单词.如果没有数组成员,则${name[@]}展开为空.
这完全符合它所说的关于位置参数扩展的说法"$@".并不是说数组和位置参数的行为没有其他的不一致......但对我来说,并没有暗示这两个细节之间应该是不一致的.
继续,
$ arr=()
$ echo "${arr[@]}"
bash: arr[@]: unbound variable   # as we've observed.  BUT...
$ echo "${#arr[@]}"
0                                # no error
$ echo "${!arr[@]}" | cat -e
$                                # no error
Run Code Online (Sandbox Code Playgroud)
所以arr[]不是那么没有约束我们不能得到它的元素(0)或其键的(空)列表的计数?对我来说,这些是明智的,也是有用的 - 唯一的异常似乎是${arr[@]}(和${arr[*]})扩张.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           14517 次  |  
        
|   最近记录:  |