嵌入式期望脚本返回成功或失败的bash

时间:2018-08-22 12:16:31

标签: linux bash tcl expect

我将期望脚本嵌入bash脚本中,以便将一些ftp文件放置在服务器上。 我试图让期望脚本向bash进程返回成功或失败的输出值,以便我可以对其执行操作,但是我失败了。 脚本如下所示:

sftper()
{
    local filename="$1"
    local user="user"
    local password="password"
    local host="ftpserver"
    local in=1

    IFS= read -r -d '' expect_commands <<EOD >echo_log
    spawn /usr/bin/sftp $user@$host
    expect "*assword:"
    send "$password\r"
    expect "sftp>"
    send "put $filename\r"
    expect "sftp>"
    send "bye\r"
    interact
EOD
    expect -c "${expect_commands//
    /;}"
    in="$?"
    return "$in"
}

`

请,我在做错什么,该如何解决?

1 个答案:

答案 0 :(得分:4)

脚本中最令人惊讶的一件事情是调用interact,这是一个Expect命令,它允许用户直接连接到生成的程序。但是,将bye命令发送到sftp后,它不太可能有用。 close; exit序列会更令人期待(关闭控制虚拟终端并退出Expect脚本)。

因此,我希望有更多类似的东西:

    IFS= read -r -d '' expect_commands <<EOD >echo_log
    spawn /usr/bin/sftp $user@$host
    expect "*assword:"
    send "$password\r"
    expect "sftp>"
    send "put $filename\r"
    expect "sftp>"
    send "bye\r"
    close
    exit
EOD

更一般地说,您应该考虑如果发生问题(例如,密码已过期)会发生什么,并且编写一个完整的期望脚本而不是运行所有shell引用的方法可能会更容易。我添加了一些小的解释性注释……

# Assuming this is in a file called do_sftp_put.exp

# set up the variables; first line is how to get a command line argument
set filename [lindex $argv 0]
set user "user"
set password "password"
set host "ftpserver"

# launch sftp
spawn /usr/bin/sftp $user@$host

# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"

# send the file
send "put $filename\r"
expect "sftp>"

# Shut down
send "bye\r"
close
exit

然后,您的shell脚本包装器将变得更加简单:

sftper()
{
    expect /path/to/do_sftp_put.exp "$1"
    return $?
}

这里不需要太多花哨的报价;这就是一切设计的工作方式。是的,期望脚本需要仔细的保护,以便只有您才能读取它,因为它包含实时凭据,但是您在shell代码中曾遇到过这个问题,所以这并不是什么新鲜事。


[EDIT]:当然,这仍然无法检测到错误。为此,您需要一个更复杂的脚本。最常见的错误之一是密码错误(或与用户不匹配)。为了解决这个问题,我们采取以下措施:

# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"

并将其升级为:

# login sequence
expect "*assword:"
send "$password\r"
expect {
    "password" {
        # It's asking for the password *again*; must be wrong!
        # Kill the sftp program and exit with an error code
        close
        exit 1
    }
    "sftp>"
}

弄清楚如何检测错误并不总是那么简单(您可以使用正则表达式等,并且您需要确切了解要针对的是什么),在某些情况下,最好备份并尝试完全是另一种方法。具体来说,对于sftp, I 将尝试配置SSH身份,以便我可以使用基于密钥的auth而不是基于密码的auth,因为在实践中,这在几种方面都更加安全。但是,这是对您的操作的重大更改,因此绝对不在问题范围内。