Python subprocess + scp - 无法读取所有输出

3 投票
2 回答
8708 浏览
提问于 2025-04-16 19:13

我正在尝试在两台机器之间使用SCP(安全复制协议)传输文件,但我希望在用户没有设置好私钥和公钥以实现无密码登录时程序能够失败。可惜的是,使用subprocess.Popen时,我无法捕捉到以下输出:

The authenticity of host '***' can't be established.
RSA key fingerprint is ***.
Are you sure you want to continue connecting (yes/no)

这个输出总是显示在控制台上,我无法在我的程序中检测到它。

这里有一些示例代码:

proc = subprocess.Popen(['scp', 'user@server:/location/file.txt', '/someplace/file.txt',
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
proc.wait()
print 'result: %s' % repr(proc.stderr.readline())

我尝试了很多其他的组合,但这个代码仍然让我输入是/否,而不是让Python来处理。至少当我输入“否”时,我得到了:

result: 'Host key verification failed.\r\n'

2 个回答

3

我之前也遇到过类似的情况,不过对我来说那次是有帮助的。我觉得ssh和相关的工具其实并不是直接读取输入(stdin)并在输出(stdout或stderr)上打印,而是以一种特殊的方式直接和你正在使用的终端连接。

我认为这样做的原因是,它们应该能够直接和用户对话,即使是在通过一些外壳脚本运行的时候,因为用户知道密码,而不是调用脚本(而且它们可能故意不想让调用脚本有机会截取密码)。

[补充说明]:根据我系统上的手册,scp确实有一个选项可能可以满足你的需求:

 -B      Selects batch mode (prevents asking for passwords or passphrases).
3

提示信息 'The authenticity of host '***' can't be established' 的意思是,你连接的机器还没有被告知要把对方(服务器)的身份保存到 known_hosts 文件里,所以它在问你是否信任这台机器。你可以设置 SSH 客户端,让它自动添加这个身份,而不需要你每次都确认。

你可以试试这个:

proc = subprocess.Popen(['scp', '-o BatchMode=yes',
                                'user@server:/location/file.txt',
                                '/someplace/file.txt'],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
proc.wait()
print 'result: %s' % repr(proc.stderr.readline())

用上面的代码,我得到了:

me@myMachine:~$ python tmp.py 
result: 'Host key verification failed.\r\n'
me@myMachine:~$

如果我禁用 StrictHostKeyChecking,我得到:

me@myMachine:~$ python tmp.py
result: 'Permission denied (publickey,password,keyboard-interactive).\r\n'
me@myMachine:~$ python tmp.py

所以看起来它是在开启 BatchMode 的情况下,从错误输出中打印了第一行内容 :)

撰写回答