29

我正在尝试使用 python 子进程模块登录到一个安全的 ftp 站点,然后获取一个文件。但是,我一直在尝试在请求时发送密码。到目前为止,我有以下代码:

from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate('password')

这仍然在密码提示处停止。如果我手动输入密码,它会转到 ftp 站点,然后在命令行上输入密码。我见过人们建议使用 pexpect 但长话短说我需要一个标准的库解决方案。反正有子进程和/或任何其他标准库吗?我在上面忘记了什么?

4

12 回答 12

12

尝试

proc.stdin.write('yourPassword\n')
proc.stdin.flush()

那应该行得通。

您所描述stdin=None的听起来像是子进程继承父进程(您的 Python 程序)的标准输入的位置。

于 2010-03-05T15:22:38.507 回答
6

也许您应该改用expect类库?

例如Pexpect示例)。还有其他类似的 python 库。

于 2010-03-05T15:29:52.137 回答
4
from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate(input='password')

尝试在通信中使用 input='password',这对我有用。

于 2018-01-19T09:36:39.560 回答
3

用于ParamikoSFTP。对于其他任何事情,这都有效:

import subprocess

args = ['command-that-requires-password', '-user', 'me']

proc = subprocess.Popen(args, 
                        stdin=subprocess.PIPE, 
                        stdout=subprocess.PIPE, 
                        stderr=subprocess.PIPE)

proc.stdin.write('mypassword\n')
proc.stdin.flush()

stdout, stderr = proc.communicate()
print stdout
print stderr
于 2016-12-12T04:47:01.943 回答
1

我建议放弃子流程方法并使用 paramiko 包进行 sftp 访问。

于 2010-03-05T18:42:48.433 回答
1

出于某种原因,我无法在这里获得任何标准库答案来为我工作——所有这些都遇到了非常奇怪的问题。这里的其他人:无法使用子进程 [python] 向进程提供密码也有同样的问题,并得出结论,最终你只需要使用 pexpect 就可以发送密码。

我想在这里添加我的最终代码,以节省遇到类似问题的任何人的时间,因为我在这上面浪费了很多时间(Python 3,2020):

ssh_password = getpass("user's password: ")
ssh_password = (ssh_password + "\n").encode()

scp_command = 'scp xx.xx.xx.xx:/path/to/file.log /local/save/path/'

child = pexpect.spawn(scp_command)
# make output visible for debugging / progress watching
child.logfile = sys.stdout.buffer

i = child.expect([pexpect.TIMEOUT, "password:"])
if i == 0:
    print("Got unexpected output: {} {}".format(child.before, child.after))
    return
else:
    child.sendline(ssh_password)
child.read()

上面的代码运行 SCP 命令将文件从远程服务器拉到本地计算机 - 根据需要更改服务器 IP 和路径。

要记住的关键事项:

  • 必须有一个pexpect.TIMEOUTin the child.expect 电话
  • 必须将传入的任何字符串编码为字节,并且必须使用默认编码
  • 将 pexpect 输出写入 sys.stdout.buffer 以便您可以实际看到发生了什么
  • child.read()最后必须有一个
于 2020-09-21T02:34:20.417 回答
0

同样的问题困扰了我一个星期。我必须通过子进程安全地提交来自用户输入的密码,因为我试图避免引入命令注入漏洞。这是我在同事的帮助下解决问题的方法。

import subprocess

command = ['command', 'option1', '--password']
subprocess.Popen(command, stdin=subprocess.PIPE).wait(timeout=60)

.wait(timeout=int) 是最重要的组件,因为它允许用户向标准输入提供输入。否则,超时默认为 0,使用户没有时间输入输入,从而导致 None 或 null 字符串。让我永远弄清楚这一点。

对于您知道必须多次执行此操作的重复用例,您可以覆盖 popen 函数并将其用作私有方法,同一程序员告诉我,如果您预计其他人会感兴趣,这是最佳实践在以后维护代码时,您不希望他们弄乱它。

def _popen(cmd):
   proc_h = subprocess.Popen(cmd, stdin=subprocess.PIPE)
   proc_h.wait(timeout=60)
   return proc_h.poll() == os.EX_OK

如果要提示用户输入,则删除 stdout=subprocess.PIPE 很重要。否则,该过程似乎会挂起 60 秒,并且用户不会得到提示,也不会意识到他们应该提供密码。标准输出自然会转到 shell 窗口并允许用户将输入传递给 popen()。

另外,只是为了解释为什么您返回 proc_h.poll() == os.EX_OK,如果命令成功,它会返回 0。这只是 c 风格的最佳实践,当您想要在函数失败的情况下返回系统错误代码时,同时考虑到返回 0 将被解释器视为“假”的事实。

于 2018-03-26T17:47:34.890 回答
0

这是一个使用 expect 的纯 Python 解决方案 - 而不是 pexpect。

如果在 Ubuntu 上,您首先需要安装期望:

sudo apt install expect

Python 3.6 或更高版本:

def sftp_rename(from_name, to_name):
    sftp_password = 'abigsecret'
    sftp_username = 'foo'
    destination_hostname = 'some_hostname'
    from_name = 'oldfilename.txt'
    to_name = 'newfilename.txt'
    commands = f"""
spawn sftp -o "StrictHostKeyChecking no" 
{sftp_username}@{destination_hostname}
expect "password:"
send "{sftp_password}\r"
expect "sftp>"
send "rename {from_name} {to_name}\r"
expect "sftp>"
send "bye\r"
expect "#"
"""
    sp = subprocess.Popen(['expect', '-c', commands], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
于 2018-08-10T06:18:01.433 回答
0

因为你想要的只是抓取一个文件,所以我正在尝试使用“子进程”,但它对我不起作用。所以现在我正在使用 paramiko,这是我的代码:这是我在网上找到的一个教程 使用 python 的 paramiko 将文件从本地服务器传输到远程服务器,反之亦然“https://www.youtube.com/watch?v= dtvV2xKaVjw"

下面是我将一个文件夹中的所有文件从 Linux 传输到 Windows 的代码

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='11.11.11.1111', username='root', password='********', port=22)
sftp_client = ssh.open_sftp()
source_folder = '/var/ftp/file_pass'
local_folder = 'C:/temp/file_pass'
inbound_files = sftp_client.listdir(source_folder)
print(inbound_files)

for ele in inbound_files:
    try:
        path_from = source_folder + '/' + ele
        path_to = local_folder + '/'+ ele
        sftp_client.get(path_from, path_to)
    except:
        print(ele)

sftp_client.close()
ssh.close()
于 2020-12-07T18:59:31.557 回答
-1
import subprocess

args = ['command', 'arg1', 'arg2']

proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE)

proc.stdin.write(b'password') ##The b prefix is necessary because it needs a byte type

proc.stdin.flush()

stdout, stderr = proc.communicate()

print(stdout)

print(stderr)
于 2019-07-22T16:11:34.033 回答
-2

最安全的方法是预先提示输入密码,然后将其输入命令。提示输入密码将避免将密码保存在代码中的任何位置。这是一个例子:

from getpass import getpass
from subprocess import Popen, PIPE

password = getpass("Please enter your password: ")
proc = Popen("sftp user@server stop".split(), stdin=PIPE)
# Popen only accepts byte-arrays so you must encode the string
proc.communicate(password.encode())
于 2019-05-21T17:41:14.950 回答
-2

您只是忘记了密码中的回车行(也就是用户按 Enter)。

from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate('password\n'.encode())

.encode()因为默认情况下proc.communicate()接受类似字节的对象。

于 2019-10-29T13:47:47.870 回答