【问题标题】:Erratic behaviour of expect shell when passing arguments to shell script将参数传递给 shell 脚本时,expect shell 的异常行为
【发布时间】:2014-12-01 22:58:34
【问题描述】:

这段代码在没有命令行参数的情况下工作正常,但在我将 IP 作为参数传递给脚本时登录到 linux 框后停止

bash -x -o igncr Master.sh 10.104.24.196

我不知道发生了什么,任何帮助将不胜感激。

if [ "$#" -eq 0  ]; then
IP="10.104.24.196"
else
IP="$1"
fi
PWD="something"
echo "Connecting to $IP with password:$PWD"
> ~/.ssh/known_hosts
/usr/bin/expect -<< EOD
set timeout -1
spawn ssh "$IP" -l root
expect "(yes/no)?"
send "yes\n"
expect "password"
    send "$PWD\n" 
    expect "$*" <- stops here
    send  "cd somewhere\n"
    send "./db_deploy.sh\n"
    expect "Script execution completed."
        send "cd somewhere\n"
        send "./apps_deploy.sh\n"
        expect "Script execution completed."
            send "exit\n"
expect eof
EOD
#dosomething else

【问题讨论】:

    标签: bash expect


    【解决方案1】:

    问题是因为expect "$*"

    如果要匹配文字的美元符号($),则在双引号内使用时应使用以下方式。

    expect {\\\$}
    

    由于$ 符号对于tclexpect 都是特殊的,为了匹配文字的美元符号,我们需要用反斜杠两次转义它,当然还要再用一个反斜杠来转义反斜杠本身。

    还有2个可以做的增强功能如下,

    要通过expect 发送“输入/返回”键,我们建议使用\r,而不是\n。 (虽然你的问题没什么大不了的。:))

    在生成 ssh session 之前,您将覆盖 known_hosts 文件 (&gt; ~/.ssh/known_hosts),因此您期望只有当主机是系统新主机时才会出现“(是/否)”。

    spawn ssh "$IP" -l root
    expect "(yes/no)?
    

    exp_continue 的帮助下,我们可以在不覆盖 known_hosts 的情况下进行处理。 (但是,如果每次删除已知主机是你的真实意图,你不需要添加这部分)

    通过在您的脚本中组合这些更改,它将如下所示,

    #!/bin/bash
    if [ "$#" -eq 0  ]; then
    IP="10.104.24.196"
    else
    IP="$1"
    fi
    PWD="something"
    echo "Connecting to $IP with password:$PWD" 
    # I have commented this line, since I am using exp_continue.
    # If you don't want, then keep your code as such
    #> ~/.ssh/known_hosts
    /usr/bin/expect -<< EOD
    set timeout 60; # 1 min of timeout 
    spawn ssh "$IP" -l root
    expect { 
            # you can keep your old code here if you want.
            "(yes/no)" {send "yes\r";exp_continue}
            "password" 
    }
    send "$PWD\r" 
    expect {\\\$}
    send  "cd somewhere\r"
    send "./db_deploy.sh\r"
    expect "Script execution completed."
    send "cd somewhere\r"
    send "./apps_deploy.sh\r"
    expect "Script execution completed."
    send "exit\r"
    expect eof
    EOD
    

    除了将expect脚本直接嵌入bash脚本之外,你可以单独保存文件并调用expect脚本如下,

    expect -c yourscript.exp
    

    查看here 以了解在将期望脚本嵌入 bash 脚本时如何使用双引号和单引号。

    更新:错过timeout 值我是多么可怜。

    expect 的默认超时值为 10 秒。这可以通过设置一个新值来改变。

    set timeout 60; # This value is in terms of seconds.
    

    通过将超时设置为 -1,我们让它无限等待。您已经使用了该值。尝试将其更改为其他值(例如 60,即 1 分钟)。

    也许,在您的情况下,如果 $ 没有匹配到,它将照此进行。如果您想优雅地处理timeout,您应该使用以下内容。

    expect {
             {\\\$} {puts "matched dollar sign"}
             timeout { puts "timeout happened"}
    }
    

    这仍然不能准确回答您的问题。您可以尝试使用带有-d 标志的expect 并在您的问题中分享输出吗?以便我们为您提供帮助。

    【讨论】:

    • with expect {\\\\$} 它总是在有或没有命令行参数的情况下停在那里!
    • 而且我不明白传递参数是如何影响期望 shell 的。我的代码在没有参数传递时有效。
    • @raynaya:哎呀。我的错。刚刚发现了问题。请参阅更新的答案。 :)
    • 谢谢。这将解决它卡住的问题,但无论有没有命令行参数,shell的输出仍然应该相同,所以无法理解为什么在我传递参数时它会卡住。我将检查 -d 标志。实际上我需要 -1 超时值,因为某些活动会花费很多时间。
    • 默认情况下,exp_continue 会重置 timeout 计时器。如果使用-continue_timer 标志调用exp_continue,则不会重新启动计时器。除此之外,exp_continue 除了让expect 再循环一次之外没有任何影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 2014-08-12
    • 2011-05-30
    相关资源
    最近更新 更多