我正在 bash 中编写一个脚本,旨在为我的一个项目运行一些测试,但我遇到了一种奇怪的行为。
在我的代码中,我有一个函数
test_it
,它接受$info:要输出的信息,$type
:一种测试类型,$files
:文件名列表,$options
:每次迭代时传递的参数到“./prog”,$optdesc
:描述选项的字符串,以及 $precond
:描述 $files 中每个文件的前提条件的字符串数组。
#!/bin/sh
test_it() {
info=$1
type=$2
files=$3
options=$4
optdesc=$5
precond=$6
for idx in ${!files[@]}
do
filename="log/$type/$filed-$optdesc.log"
if [[ ! -f $filename ]]; then
touch $filename
fi
if [[ "${options[@]}" = "" ]]
then
./prog $file -precondition "${precond[idx]}" > $filename
else
./prog $file "${options[@]}" -precondition "${precond[idx]}" > $filename
fi
done
}
我首先使用此设置运行它
## termination (CFG) with default setting:
## -domain boxes
## -joinbwd 2
type="termination"
info="info1"
files=("tests/termination/boolean.c"
"tests/termination/cacm2009a.c"
"tests/termination/cav2006.c"
"tests/termination/example1.c"
"tests/termination/example2a.c"
"tests/termination/tacas2013a.c" )
precond=("${files[@]/*/"true"}")
options=("-ctl-cfg" "AF{exit: true}")
optdesc="termCFG"
test_it "$info" $type $files $options $optdesc $precond
这里一切都很顺利。然后我运行了第二个测试服。
## conditional termination
type="termination"
info="info2"
files=( "tests/termination/example7.c"
"tests/termination/sas2014a.c"
"tests/termination/sas2014c.c"
"tests/termination/tap2008a.c"
"tests/termination/tap2008b.c"
"tests/termination/tap2008c.c"
"tests/termination/tap2008d.c"
"tests/termination/tap2008e.c"
"tests/termination/widening3.c")
precond=( "x > 6"
"r <= 0"
"x < 0"
"x < 25 || x > 30"
"x <= 30 && x >= 0 || x > 35 || x < -5"
"x < 30"
"x <= 0"
"x <= 11"
"x <= 0")
options=()
optdesc="condtermAST"
test_it "$info" $type $files $options $optdesc "$precond"
这里我有一个问题,在函数
test_it
中,如果我打印我获得的每个变量的值:
precond == ("r <= 0" "x < 0" "x < 25 || x > 30" "x <= 30 && x >= 0 || x > 35 || x < -5"
"x < 30"
"x <= 0"
"x <= 11"
"x <= 0")
所以这里
$precond
的第一个元素“x > 6”消失了,但这还不是全部,我们还有
optdesc=="x>6"
所以我不明白为什么争论中会有这种“转变”。它似乎来自“$options”数组。事实上,我可以通过用
调用
test_it
来解决这个问题
test_it "$info" $type $files "$options" $optdesc "$precond"
有人知道为什么 bash 会这样吗?请^^ 我对 bash 语义的了解不足以给出原因。
我认为您的脚本的主要问题是 bash 数组的使用不当。 首先,you shebang 是为了
sh
。它不支持数组,因此脚本应该有一个错误。
由于您没有提及,我假设您使用 bash 命令运行脚本,或者操作系统中的 sh
是 bash。
test_it "$info" $type $files "$options" $optdesc "$precond"
在这一行中,变量
files
、options
和 precond
是数组,但您将它们作为常规变量进行了扩展。结果,仅替换第一个值。这是实际收到的论点test_it
:
test_it info2 termination tests/termination/example7.c condtermAST "x > 6"
由于
options
是一个空数组并且未加引号进行扩展,因此没有参数传递给 test_it
。这也许可以解释为什么参数的索引是错误的。
由于向函数提供多个数组作为参数很困难,我认为您应该更改脚本的逻辑,将循环移到函数之外
test_it
。例如,类似:
test_it() {
info="$1"
type="$2"
file="$3"
optdesc="$4"
precond="$5"
options=("${@:6}") # all arguments after the sixth one
filename="log/$type/$file-$optdesc.log" # typo in $file variable ?
if [[ ! -f "$filename" ]]; then
touch "$filename" # quote all variables to prevent word splitting!
fi
# it is not necessary to check if options is empty
./prog "$file" "${options[@]}" -precondition "${precond}" > "$filename" # quote all variables to prevent word splitting!
}
# all variable definitions...
for i in "${!files[@]}" # move loop here
do
test_it "$info" "$type" "${files[i]}" "$optdesc" "${precond[i]}" "${options[@]}" # options is moved the back so we can pass any number of parameters
done
另一种方法是直接访问
test_it
中的数组变量,而不从函数参数中设置它们