嵌入式期望脚本 return 成功或失败 bash
Embedded expect script return success or failure to bash
我在 bash 脚本中嵌入了一个 expect 脚本,以便在服务器上放置一些 ftp 文件。
我试图让 expect 脚本 return 向 bash 过程输出成功或失败的值,以便我可以对其采取行动,但我失败得很惨。
脚本如下所示:
sftper()
{
local filename=""
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"
}
`
拜托,我做错了什么,我该如何解决这个问题?
脚本中最令人惊讶的是您调用了 interact
,这是一个 Expect 命令,允许用户直接连接到生成的程序。但是,在您向 sftp 发送 bye
命令后,它不太可能有用; 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
更一般地说,您应该考虑如果出现问题会发生什么(例如,如果密码已过期),并且编写完整的 expect 脚本可能比 运行 gauntlet 更容易所有 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 ""
return $?
}
这里不需要太多花哨的引用;这就是一切设计工作的方式。是的,expect 脚本需要仔细保护,只有您可以阅读它,因为它包含实时凭据,但您之前在 shell 代码中遇到过这个问题,所以这不是什么新鲜事。
[编辑]:当然,这仍然没有检测到错误。为此,您需要一个更复杂的脚本。最常见的错误之一是密码错误(或与用户不匹配)。为了解决这个问题,我们采取这一点:
# 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 身份,以便我可以使用基于密钥的身份验证而不是基于密码的身份验证,因为这在实践中以多种方式更加安全.但是,这对您的操作来说是一个重大变化,因此绝对不在问题范围内。
我在 bash 脚本中嵌入了一个 expect 脚本,以便在服务器上放置一些 ftp 文件。 我试图让 expect 脚本 return 向 bash 过程输出成功或失败的值,以便我可以对其采取行动,但我失败得很惨。 脚本如下所示:
sftper()
{
local filename=""
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"
}
`
拜托,我做错了什么,我该如何解决这个问题?
脚本中最令人惊讶的是您调用了 interact
,这是一个 Expect 命令,允许用户直接连接到生成的程序。但是,在您向 sftp 发送 bye
命令后,它不太可能有用; 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
更一般地说,您应该考虑如果出现问题会发生什么(例如,如果密码已过期),并且编写完整的 expect 脚本可能比 运行 gauntlet 更容易所有 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 ""
return $?
}
这里不需要太多花哨的引用;这就是一切设计工作的方式。是的,expect 脚本需要仔细保护,只有您可以阅读它,因为它包含实时凭据,但您之前在 shell 代码中遇到过这个问题,所以这不是什么新鲜事。
[编辑]:当然,这仍然没有检测到错误。为此,您需要一个更复杂的脚本。最常见的错误之一是密码错误(或与用户不匹配)。为了解决这个问题,我们采取这一点:
# 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 身份,以便我可以使用基于密钥的身份验证而不是基于密码的身份验证,因为这在实践中以多种方式更加安全.但是,这对您的操作来说是一个重大变化,因此绝对不在问题范围内。