Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用subprocess.Popen通过SSH或SCP发送密码_Python_Linux_Ssh_Python 3.x_Subprocess - Fatal编程技术网

Python 使用subprocess.Popen通过SSH或SCP发送密码

Python 使用subprocess.Popen通过SSH或SCP发送密码,python,linux,ssh,python-3.x,subprocess,Python,Linux,Ssh,Python 3.x,Subprocess,我正在尝试使用subprocess.Popen运行(安全复制)命令。登录需要我发送密码: from subprocess import Popen, PIPE proc = Popen(['scp', "user@10.0.1.12:/foo/bar/somefile.txt", "."], stdin = PIPE) proc.stdin.write(b'mypassword') proc.stdin.flush() 这会立即返回一个错误: user@10.0.1.12's passwor

我正在尝试使用
subprocess.Popen
运行(安全复制)命令。登录需要我发送密码:

from subprocess import Popen, PIPE

proc = Popen(['scp', "user@10.0.1.12:/foo/bar/somefile.txt", "."], stdin = PIPE)
proc.stdin.write(b'mypassword')
proc.stdin.flush()
这会立即返回一个错误:

user@10.0.1.12's password:
Permission denied, please try again.
我确信密码是正确的。我可以通过在shell上手动调用
scp
来轻松验证它。那么为什么这不起作用呢

注意,有许多类似的问题,询问
subprocess.Popen
并为自动SSH或FTP登录发送密码:



这些问题的答案不起作用和/或不适用,因为我使用的是Python 3。

您链接的第二个答案建议您使用Pexpect(这通常是与需要输入的命令行程序交互的正确方式)。有一个适用于python3的函数,您可以使用它。

这里有一个函数,使用
pexpect
使用密码来
ssh

import pexpect

def ssh(host, cmd, user, password, timeout=30, bg_run=False):                                                                                                 
    """SSH'es to a host using the supplied credentials and executes a command.                                                                                                 
    Throws an exception if the command doesn't return 0.                                                                                                                       
    bgrun: run command in the background"""                                                                                                                                    

    fname = tempfile.mktemp()                                                                                                                                                  
    fout = open(fname, 'w')                                                                                                                                                    

    options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'                                                                         
    if bg_run:                                                                                                                                                         
        options += ' -f'                                                                                                                                                       
    ssh_cmd = 'ssh %s@%s %s "%s"' % (user, host, options, cmd)                                                                                                                 
    child = pexpect.spawn(ssh_cmd, timeout=timeout)  #spawnu for Python 3                                                                                                                          
    child.expect(['[pP]assword: '])                                                                                                                                                                                                                                                                                               
    child.sendline(password)                                                                                                                                                   
    child.logfile = fout                                                                                                                                                       
    child.expect(pexpect.EOF)                                                                                                                                                  
    child.close()                                                                                                                                                              
    fout.close()                                                                                                                                                               

    fin = open(fname, 'r')                                                                                                                                                     
    stdout = fin.read()                                                                                                                                                        
    fin.close()                                                                                                                                                                

    if 0 != child.exitstatus:                                                                                                                                                  
        raise Exception(stdout)                                                                                                                                                

    return stdout

使用
scp

Pexpect应该可以实现类似的功能:pxsh


我猜有些应用程序使用stdin与用户交互,有些应用程序使用终端交互。在这种情况下,当我们使用管道写入密码时,我们正在写入stdin。但SCP应用程序从终端读取密码。由于子流程不能使用终端与用户交互,但只能使用stdin进行交互,因此我们不能使用子流程模块,必须使用pexpect使用scp复制文件


请随意更正。

OpenSSH
scp
实用程序调用
ssh
程序以建立到远程主机的ssh连接,ssh进程处理身份验证。
ssh
实用程序不接受命令行或其标准输入上的密码。我相信这是OpenSSH开发人员深思熟虑的决定,因为他们认为人们应该使用更安全的机制,比如基于密钥的身份验证。任何调用ssh的解决方案都将遵循以下方法之一:

  • 使用身份验证,而不是密码
  • 使用或类似工具自动响应密码提示
  • 使用(滥用)SSH_ASKPASS功能获取
    SSH
    ,通过调用另一个命令获取密码,如或所述,或在一些答案中所述
  • 让SSH服务器管理员启用并使用它。请注意,基于主机的身份验证仅适用于某些网络环境。请参阅其他注释和
  • 使用perl、python、java或您最喜欢的语言编写您自己的ssh客户端。大多数现代编程语言都有可用的ssh客户端库,您可以完全控制客户端获取密码的方式
  • 下载并构建一个修改版的
    ssh
    ,它可以按照您想要的方式工作
  • 使用不同的ssh客户端。有免费的和商业的。其中一个可能比OpenSSH客户端更适合您的需要
  • 在这种情况下,假设您已经从python脚本调用了
    scp
    ,那么以下方法之一似乎是最合理的方法:

  • 使用PythonExpect模块调用
    scp
    ,并向其提供密码
  • 使用python ssh实现来执行此ssh任务,而不是调用外部程序

  • 这是我基于pexpect的scp函数。除密码外,它还可以处理通配符(即多个文件传输)。 要处理多个文件传输(即通配符),我们需要通过shell发出命令。参考

    它可以这样使用:

    params = {
        'src': '/home/src/*.txt',
        'user2': 'userName',
        'host2': '192.168.1.300',
        'tgt': '/home/userName/',
        'pwd': myPwd(),
        'opts': '',
    }
    
    scp(**params)
    

    我不熟悉这段代码,但您是否尝试使用-p参数?还有一个密钥交换作为验证方法?使用-p我的意思是“-p mypassworduser@10.0.1.12:/foo/bar/somefile.txt“我不知道您是否可以that@diego2k据我所知,scp不接受通过命令行输入密码的开关(其手册页不包含此类内容)。一般来说,在命令行上提供密码是不好的做法,因为这将被记录在.bash_history中。也许您可以通过创建一个文件来解决此问题。
    scp
    是否需要一个
    -r
    来复制
    (目录)?如果您正在努力使
    pexpect
    正常工作,我在下面添加了一个函数,应该会有所帮助。注意:现在常规支持Python 3。谢谢。这帮了我的忙。我正在查,你能告诉我这句话是什么意思吗?”-q-oStrictHostKeyChecking=no-oUserKnownHostsFile=/dev/null-oPubkeyAuthentication=no'@alfonso这些是您将在命令行或
    .ssh/config
    中传递给ssh的选项,而不使用
    -o
    。第一个命令告诉ssh,如果主机更改了其密钥,则不要抱怨,因为自您上次使用该命令后,它可能已重新安装。第二种方法是使用/dev/null而不是.ssh/known_hosts,因此如果重新安装时出现重复条目警告,它将再次停止抱怨。最后几天不使用强制输入密码的密钥。对于python 3,应使用
    spawnu
    而不是
    spawn
    ,根据避免
    write()参数必须是str,而不是bytes
    导入tempfile并应添加
    导入pexpect
    pip install pexpect
    pip3 install pexpect
    可以安装所需的软件包导入pxsh\snap install microk8s
    import pexpect
    
    def scp(src,user2,host2,tgt,pwd,opts='',timeout=30):
        ''' Performs the scp command. Transfers file(s) from local host to remote host '''
        cmd = f'''/bin/bash -c "scp {opts} {src} {user2}@{host2}:{tgt}"'''
        print("Executing the following cmd:",cmd,sep='\n')
    
        tmpFl = '/tmp/scp.log'
        fp = open(tmpFl,'wb')
        childP = pexpect.spawn(cmd,timeout=timeout)
        try:
            childP.sendline(cmd)
            childP.expect([f"{user2}@{host2}'s password:"])
            childP.sendline(pwd)
            childP.logfile = fp
            childP.expect(pexpect.EOF)
            childP.close()
            fp.close()
    
            fp = open(tmpFl,'r')
            stdout = fp.read()
            fp.close()
    
            if childP.exitstatus != 0:
                raise Exception(stdout)
        except KeyboardInterrupt:
            childP.close()
            fp.close()
            return
    
        print(stdout)
    
    params = {
        'src': '/home/src/*.txt',
        'user2': 'userName',
        'host2': '192.168.1.300',
        'tgt': '/home/userName/',
        'pwd': myPwd(),
        'opts': '',
    }
    
    scp(**params)