我在几个Linux机器上运行此代码段,并在Solaris 10机箱上运行bash 3.6(iirc)。但是,在带有GNU bash, version 4.4.11(1)-release (sparc-sun-solaris2.11)
的Solaris 11机器上,它会出现以下错误。
#!/bin/env bash
CLEAN_COUNT() {
local L_STRING=$(sed '/[^[:graph:][:space:]]/{
s/[^[:graph:][:space:]]//g; s/\[[0-9]*m//g; s/(B//g
}' <<<$*) || return 1
echo ${#L_STRING}
}
f() {
ARGS=($@)
echo $((${#ARGS[1]:-0} - $(CLEAN_COUNT ${ARGS[1]:-0}) ))
}
f one two three four
收到错误:./gather_data.bash: line 15: ${#ARGS[1]:-0} - $(CLEAN_COUNT ${ARGS[1]:-0}) : bad substitution
我已经在其自己的脚本中隔离了上述代码,我已经将该框中的shopt和set -o
设置与另一个设置进行了比较。我很困惑。如果我可以在没有替换的情况下使代码工作,即使ARGS没有元素1而且我正在运行set -o nounset
,那么我将使用另一段代码。
答案 0 :(得分:2)
影响这种情况的变化发生在Bash 4.3和Bash 4.4中。观察:
Bash 4.2中没有错误:
$ docker run --rm -it bash:4.2 bash -u
bash-4.2$ bash --version | head -n 1
GNU bash, version 4.2.53(2)-release (x86_64-pc-linux-musl)
bash-4.2$ declare -a var && echo "${#var[1]:-1}"
0
但这实际上并没有打印我的默认值:var[1]
是空字符串,因此是0
。 -u
似乎忽略了var
没有元素。 echo "${#var[1]:-1}"
,echo "${#var[1]}"
和echo "${#var[1]}"
之间的行为没有区别,它们都打印0
。
Bash 4.3抱怨未绑定的变量:
$ docker run --rm -it bash:4.3 bash -u
bash-4.3$ bash --version | head -n 1
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-musl)
bash-4.3$ declare -a var && echo "${#var[1]:-1}"
bash: var: unbound variable
Bash 4.4抱怨替换:
$ docker run --rm -it bash:4.4 bash -u
bash-4.4$ bash --version | head -n 1
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-musl)
bash-4.4$ declare -a var && echo "${#var[1]:-1}"
bash: ${#var[1]:-1}: bad substitution
即使没有set -u
:
bash-4.4# set +o nounset
bash-4.4# declare -a var && echo "${#var[1]:-1}"
bash: ${#var[1]:-1}: bad substitution
此外,${#var:-1}
被视为&#34;不良替代&#34;在所有版本中,即使没有set -u
:
$ for v in 3.2 4.{0..4}; do docker run --rm -it bash:$v; done
bash-3.2# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-3.2# exit
exit
bash-4.0# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-4.0# exit
exit
bash-4.1# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-4.1# exit
exit
bash-4.2# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-4.2# exit
exit
bash-4.3# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-4.3# exit
exit
bash-4.4# echo "${#var:-1}"
bash: ${#var:-1}: bad substitution
bash-4.4# exit
exit
我无法在NEWS
中看到有关此行为的任何更改,但似乎有道理,因为${#var[0]:-1}
默认情况下不会默认为1
,所以现在行为在标量和数组之间是一致的。
这就是说,我按照以下方式重写你的功能:
f () {
local args=("$@")
if [[ -z ${args[1]:-} ]]; then
echo 0
else
echo $(( ${#args[1]} - $(clean_count "${args[1]}") ))
fi
}
args
本地功能"$@"
以避免在分配数组元素之前拆分args[1]
是否为空字符串,确保${args[1]:-}
或者,如果f ()
不是简化版,并且您永远不会访问您展示的元素以外的其他元素,则可以进一步简化为
f () {
if [[ -z ${2:-} ]]; then
echo 0
else
echo $(( ${#2} - $(clean_count "$2") ))
fi
}