跳转至主要内容
在我的上一篇博客中,我谈到了使用FTP自动传输文件的问题。使用FTP有三个问题。首先,你的密码是以明文形式在网络上发送的,任何有协议分析器的人都可以使用。第二,你的数据也是以明文形式发送的。第三,你必须在模块的某个地方记录你的密码,无论是在宏中还是在.netrc文件中。由于这些问题,许多站点已经或正在考虑强制使用SFTP,即SSH的安全FTP子系统来代替FTP。然而,你不能在你的命令宏中用sftp代替ftp(图1)并期望它能工作(图2)。

 

&attach_input
sftp 172.16.1.116
nd
MYPASSWORD
put foo
&if (command_status) ^= 226 &then &goto ERROR1
get bar
&if (command_status) ^= 226 &then &goto ERROR2
quit
&
&label ERROR1
..display_line Could not put file
quit
&return
&
&label ERROR2
..display_line Could not get file
quit
&return

图1 - sftp1.cm - 在命令宏中用sftp替换ftp命令。

 

sftp1
Connecting to 172.16.1.116...
dup2: Bad file number.
Error on line 3 of sftp1.
command_processor: Object not found. nd. In command macro
%phx_vos#m15_mas>SysAdmin>Noah_Davids>sftp1.cm
ready  12:39:59

 

图2 - 运行sftp1.cm
问题是原生VOS命令和POSIX开源处理输入的方式不兼容。然而,SFTP和FTP一样,允许你创建一个带有请求列表的文件(图3),它将自动运行(图4)。

 


put foo
get bar

 

图3 - sftp2.input - 包含执行sftp请求的文件。

 


sftp -b sftp2_input nd@172.16.1.116
nd@172.16.1.116's password:
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/foo
sftp> get bar
Couldn't stat remote file: No such file or directory
File "/SysAdmin/Noah_Davids/bar" not found.
Ready  13:06:45

 

图4 - 输入请求文件和密码提示的执行情况
在图4中你会注意到,sftp提示输入密码。没有办法在输入文件中加入密码。绕过密码提示的唯一方法是使用公钥认证(图5)。

 

sftp -b sftp2_input nd@172.16.1.116
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/foo
sftp> get bar
Couldn't stat remote file: No such file or directory
File "/SysAdmin/Noah_Davids/bar" not found.
Ready  13:12:28

 

图5--用输入的请求文件执行,使用公钥认证来消除密码提示

 

你可以在这里找到一篇关于如何设置公钥认证的文章--http://members.cox.net/ndav1/self_published/publickey_authentication_setup.html。

遗憾的是,sftp只会陆续执行输入文件中的所有请求,没有任何机制来测试传输是否成功。

既然不能使用命令宏,有没有其他的选择?gnu_tools产品中提供了一个名为expect的程序。它可以用来发送命令,等待任何数量的不同的响应,并根据它在输出流中看到的东西做一些事情。我不是 expect 专家,但图 6 中的脚本可以帮助你开始使用。如果你在网上搜索"期望脚本",你会发现很多参考资料,可以帮助你定制我的简单例子。

 

# If we get an end-of-file (eof) it means that the sftp process
# terminated. Report the last command that was sent.
#
proc goteof {cmd} {
puts "sftp connection unexpectedly closed n"
puts "last text received wasn"
puts "<<"
puts $cmd
puts ">>nnn"
exit
}
# 这个过程进行正则表达式匹配,寻找关键字符串
在从执行的命令中收集的输出中#。在这种情况下
# 我只是报告错误类型,但也可以做其他事情
#也是。我也只检查了2个错误。还有其他的。你会有
# #添加他们,因为你发现他们。
#
proc checkforerrors {buf cmd} {
如果 [regexp {.*not found} $buf] {
把"$cmd FAILED : not foundnnn"
返回1
}
如果 [regexp {.*Permission denied} $buf] {
把"$cmd FAILED : 访问问题nnn"
返回1
}
回0
}# 将超时设置为-1,所以没有超时。默认为10秒
# 而大多数文件传输都需要更长的时间。我决定不设置
#超时,你可以改变它。
设置超时-1

# 启动 sftp
spawn sftpnd@172.16.1.116

# 等待sftp提示,但如果我们得到一个认证提示,以
# yes/no 报告一个安全问题并退出。
expect {
"是/否?"{ put
"nnWe have connected to the wrong server or the server has been reloaded."

"在再次运行这个脚本之前,必须对服务器的密钥进行验证。
退出 }
sftp>
}

# 换到一个方便的目录进行测试
发送 "cd sftp_testr"
预期 {
eof { goteof "cd sftp_test" }
sftp>
}

# 调用检查错误的方法,将所有收集到的字符传上去。
# sftp>提示。也是发送到sftp的命令。如果
# checkforerrors过程返回1,则退出该脚本。同样,你可以
# 做其他事情。
如果 {[checkforerrors $expect_out(buffer) "cd sftp_test"] == 1}{ 退出 }

发送 "把门"。
预期 {
eof { goteof "put foo" }
sftp>
}
如果 {[checkforerrors $expect_out(buffer) "put foo"] == 1}.{ exit }

送出 "获得巴尔"。
预期 {
eof { goteof "get bar" }
sftp>
}
如果 {[checkforerrors $expect_out(buffer) "get bar"] == 1}.{ 退出 }

送"辞行"
期待
把"脚本donenn"

 

图6 - sftp3.exp - 期待脚本自动完成SFTP的工作

 

expect sftp3.exp
spawn sftp nd@172.16.1.116
Connecting to 172.16.1.116...
The authenticity of host 172.16.1.116(172.16.1.116)' can't be established
+.
RSA key fingerprint is 37:f4:1a:56:64:af:ab:8a:7c:0b:36:47:c5:6c:1d:1a.
Are you sure you want to continue connecting (yes/no)?
我们连接到了错误的服务器,或者服务器已经被重新加载。
在这个脚本再次运行之前,必须验证服务器密钥。

 

图7 - 执行带有安全警告的sftp3.exp期望脚本。

 

expect sftp3.exp
spawn sftp nd@172.16.1.116
Connecting to 172.16.1.116...
sftp> cd sftp_test
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/sftp_test/foo
sftp> 获取酒吧
无法统计远程文件。没有这样的文件或目录
未找到文件"/SysAdmin/Noah_Davids/sftp_test/bar"。
sftp> get bar FAILED : not foundready 10:42:11

 

图8 - 执行sftp3.exp期望脚本时没有警告,但传输失败了

最后,我在FTP博客中提到,FTP能够读取还在打开的文件,这有时会导致传输的文件不完整,我建议,如果FTP宏等待文件出现在某个位置,然后再传输,那么宏应该检查是否已经锁定。SFTP也会出现同样的问题,解决方法也是一样的。可以将文件锁检查放在命令宏中(图9),然后当文件不再锁定时,用相应的脚本调用期望。

&label AGAIN
&if (exists new_file) = 1 & (locked new_file) = 0 &then &goto EXPECT
display_line new_file not ready for transfer as of (time)
sleep -seconds 15
&goto AGAIN
&
&
&label EXPECT
expect sftp3.exp

 

图9--命令宏在调用expect之前测试文件锁的情况。

© 2020 Stratus Technologies.