Python中subprocess管道传递密码至getpass脚本失败求助
问题:通过管道向使用getpass的脚本传递密码失败
我尝试用main.py脚本通过管道标准输入给password.py传密码,但password.py用getpass.getpass()获取用户输入,用subprocess子进程管道输入时出现错误,没法完成密码传递。希望实现自动化流程,不用每次手动输入密码。
相关代码
password.py
import getpass password = getpass.getpass("Enter your password: ") if password != "test": print("wrong password") else: print("correct password")
main.py(原出错版本)
import subprocess as sp # 启动password.py作为子进程 proc = sp.Popen(["python", "password.py"], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE) # 读取输出和错误流 stdout, stderr = proc.communicate() # 打印结果 print(stdout) print(stderr) # 等待进程结束并获取返回码 returncode = proc.wait() # 检查返回码 if returncode == 0: print("Command successful") else: print("Command failed")
报错信息
b'/usr/lib/python3.8/getpass.py:91: GetPassWarning: Can not control echo on the terminal.\n passwd = fallback_getpass(prompt, stream)\nWarning: Password input may be echoed.\nEnter your password: Traceback (most recent call last):\n File "/usr/lib/python3.8/getpass.py", line 69, in unix_getpass\n old = termios.tcgetattr(fd) # a copy to save\ntermios.error: (25, \'Inappropriate ioctl for device\')\n\n During handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File "password.py", line 3, in <module>\n password = getpass.getpass("Enter your password: ")\n File "/usr/lib/python3.8/getpass.py", line 91, in unix_getpass\n passwd = fallback_getpass(prompt, stream)\n File "/usr/lib/python3.8/getpass.py", line 126, in fallback_getpass\n return _raw_input(prompt, stream)\n File "/usr/lib/python3.8/getpass.py", line 148, in _raw_input\n raise EOFError\nEOFError\n' Command failed
原因
getpass.getpass()的设计逻辑是直接与终端交互,而非从标准输入读取内容。当子进程的stdin被重定向到管道时,它无法正常控制终端的回显行为,最终抛出终端控制相关的错误并触发EOFError。
解决方案
方案1:修改password.py,支持从环境变量获取密码(推荐,最简单)
如果允许修改password.py,可以让它优先从环境变量读取密码,没有的话再用getpass手动输入:
import getpass import os # 优先读取环境变量MY_PASSWORD,不存在则使用getpass password = os.environ.get('MY_PASSWORD') or getpass.getpass("Enter your password: ") if password != "test": print("wrong password") else: print("correct password")
对应的main.py修改为:
import subprocess as sp import os # 复制当前环境变量,添加密码 env = os.environ.copy() env['MY_PASSWORD'] = 'test' # 启动子进程并传递环境变量 proc = sp.Popen(["python", "password.py"], stdout=sp.PIPE, stderr=sp.PIPE, env=env) stdout, stderr = proc.communicate() # 解码并打印输出 print(stdout.decode()) print(stderr.decode()) returncode = proc.wait() if returncode == 0: print("Command successful") else: print("Command failed")
方案2:用伪终端(pty)模拟终端交互(无需修改password.py)
如果不能修改password.py,可以用pty模块创建伪终端,让getpass以为在和真实终端交互:
import subprocess as sp import pty import os # 创建伪终端主从设备 master, slave = pty.openpty() # 启动子进程,将标准输入输出绑定到伪终端 proc = sp.Popen(["python", "password.py"], stdin=slave, stdout=slave, stderr=slave) os.close(slave) # 关闭不必要的从设备 # 向伪终端写入密码,记得加换行符模拟回车 os.write(master, b'test\n') # 读取输出内容 output = os.read(master, 1024).decode() os.close(master) # 等待进程结束并检查返回码 returncode = proc.wait() print(output) if returncode == 0: print("Command successful") else: print("Command failed")
内容的提问来源于stack exchange,提问作者Rabia Hussain
相关产品推荐
相关产品推荐

