bash 的奇怪行为(传递给可执行文件的参数溢出)

问题描述 投票:0回答:1

我正在 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 语义的了解不足以给出原因。

linux bash unix terminal sh
1个回答
0
投票

我认为您的脚本的主要问题是 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
中的数组变量,而不从函数参数中设置它们

© www.soinside.com 2019 - 2024. All rights reserved.