使用bash / expect

时间:2019-02-17 16:06:26

标签: arrays bash loops tcl expect

简单脚本无法正常工作。我花了数小时的时间进行梳理,试图发现转义和引用的正确组合以使其起作用,但我尚未成功。

我有一个K数组,我想从嵌入式的Expect脚本中循环遍历。

send_user '${list[4]}'

按预期工作,在控制台上打印数组的第四个元素。

循环语句:

incr i 1
send_user "\$i"

按预期工作,打印递增的整数值 12345 ... 等。

但是,这就是窍门。

send_user "${list[$i]}"

不起作用。无论$i的值是什么,它总是返回第一个数组元素,我无法遍历该数组。

是的,我知道用反斜杠转义$,以及单引号和双引号的效果之间的区别,等等。我已经尝试了每种组合。就像我说的,几个小时。我要么得到一个错误,什么都没有,要么得到数组的第一个元素(如示例中所示),而不考虑$i的实际值。

我还尝试将数组作为关联数组和列表直接移动到期望脚本部分。娜达问题不在于读取数组中的数据,而是使用变量而不是离散数来检索嵌入式期望代码中的数组或列表数据。

在放弃这种方法并以另一种方式重写冗长而复杂的测试工具之前,我想我会呼吁聚集在一起的人。

我在下面嵌入了一个演示测试脚本。

谢谢大家的建议。

内森

$ cat test24.sh
list=(zero one two three four)

expect <<- EXPECT_DONE

exp_internal 1

send_user '${list[4]}'

set i 0
send_user "\$i"

send_user "${list[$i]}"
incr i 1
send_user "\$i"
send_user "$list[$i]"
incr i 1
send_user "\$i"
send_user "${list[ "$i" ]}"
incr i 1
send_user "\$i"
send_user ${list[$i]}
incr i 1
send_user "\$i"
send_user "${list[$i]}"
send_user ${list[4]}
send_user "\n"

EXPECT_DONE

echo "Script done."


$ ./test24.sh
'four'0zero1zero2zero3zero4zerofour
Script done.

2 个答案:

答案 0 :(得分:3)

问题在于, shell 数组的任何扩展都必须在Tcl代码开始执行之前发生,并且您正在尝试使用Tcl变量对shell数组进行索引。最好将数组中的值作为 arguments 传递给Tcl脚本,而不是使用嵌入的对数组的引用动态生成脚本。这样一来,您可以单引号here文档,以避免在脚本内部进行任何其他转义。

expect -f - "${list[@]}" <<- 'EXPECT_DONE'

exp_internal 1

send_user [lindex argv 4]

set i 0
send_user "$i"

send_user [lindex argv $i]
incr i 1
send_user $i
send_user [lindex argv $i]
incr i 1
send_user $i
send_user [lindex argv $i]
incr i 1
send_user $i
send_user [lindex argv $i]
incr i 1
send_user $i
send_user [lindex argv $i]
send_user [lindex argv 4]
send_user "\n"

EXPECT_DONE

(对Tcl脚本中的任何错误表示歉意,距我编写任何Tcl代码已有几十年了。)

答案 1 :(得分:1)

您误解了何时/何地进行扩展。

incr i 1
讲者希望将1加到自己的变量i中。 但是shell变量i从来没有看到过。

类似地:

send_user "${list[$i]}"

由shell扩展,expect在看到命令之前。外壳程序没有名为i的变量,因此$i扩展为0(从技术上讲无内容,但是当用作列表下标时,它将被视为0),并且${list[0]}变为zero。期望收到:

send_user "zero"

重组代码的一种可能方法可能是将所有处理移入期望中。请注意'EXPECT_DONE'的单引号,以便外壳程序不会更改任何输入:

#!/bin/bash

expect <<- 'EXPECT_DONE'

    set list [list zero one two three four]

    exp_internal 1

    for {set i 0} {$i < [llength $list]} {incr i} {
        send_user "$i"
        send_user [lindex $list $i]
    }

    send_user "\n"

EXPECT_DONE

echo "Script done."

另一种方法是将所有处理移入bash:

#!/bin/bash

{
    list=(zero one two three four)

    echo "exp_internal 1"

    i=0
    while [[ $i -le ${#list} ]]; do
        echo "send_user \"$i\""
        echo "send_user \"${list[$i]}\""
        : $((i++))
    done

    echo "send_user \"\\n\""

} | expect

echo "Script done."