Python 将输出重定向到文件时,raw_input()提示消失

Python 将输出重定向到文件时,raw_input()提示消失,python,Python,我正在编写一个CLI,它接受电子邮件和身份验证密码。 电子邮件提示使用raw_input(),密码提示使用getpass()进行混淆 直接输出到控制台时,此设置工作正常,但将输出重定向到日志文件时会出现问题 示例代码: user\u email=原始输入('email:')) 用户\u password=getpass('password:') 无重定向的示例输出: 带有重定向的示例输出: 因为我知道这里需要用户输入,所以我可以键入电子邮件,按enter键,然后显示: $ python scr

我正在编写一个CLI,它接受电子邮件和身份验证密码。 电子邮件提示使用
raw_input()
,密码提示使用
getpass()
进行混淆

直接输出到控制台时,此设置工作正常,但将输出重定向到日志文件时会出现问题

示例代码:
user\u email=原始输入('email:'))
用户\u password=getpass('password:')
无重定向的示例输出: 带有重定向的示例输出: 因为我知道这里需要用户输入,所以我可以键入电子邮件,按enter键,然后显示:

$ python script_that_does_stuff.py > stuff.log
me@email.com
Password: 
输入密码后,它会像往常一样继续,但日志显示如下:

$ cat stuff.log

Email:Doing stuff...
问题: 如何强制
raw\u input()
提示符显示在控制台中,就像将输出重定向到文件时的
getpass()
提示符一样

环境 此脚本存在于传统的Python 2.7代码库中,主要在Mac OS系统上运行,偶尔在Linux上运行。

根据
getpass([prompt[,stream]])
有第二个可选参数,该参数指示要将提示打印到的输出流(
stderr

重定向输出(
stdout
)时,
getpass
的提示符仍打印到
stderr
,但
raw\u input
不支持设置输出流,因此其提示符重定向到目标文件


因此,为了解决您的问题,您还必须将电子邮件提示打印到
stderr

您可以临时覆盖
sys.stdout
,以写入终端。比如说,

import contextlib
import sys


@contextlib.contextmanager
def output_to_terminal():
    try:
        with open("/dev/tty") as f:
            sys.stdout = f
            yield
    finally:
        # Ensure sys.stdout is restored in the event of an error
        sys.stdout = sys.__stdout__


with output_to_terminal():
    x = raw_input("> ")
print(x)
(这是独立派生的;您可能需要检查Python 3的
重定向\u stdout
的源代码,也可以在
contextlib
模块中找到,并将其向后移植以供您使用。)

关于另一个问题,我似乎可以回答

简而言之,创建一个自定义输入函数:

def email_输入(提示符=无):
如果提示:
sys.stderr.write(str(提示符))
返回原始输入()
然后调用代码变为:

user\u email=email\u输入('email:'))
用户\u password=getpass('password:')
这将导致电子邮件和密码提示被发送到stderr(打印到控制台),而不会影响重定向的日志输出

$ cat stuff.log

Email:Doing stuff...
import contextlib
import sys


@contextlib.contextmanager
def output_to_terminal():
    try:
        with open("/dev/tty") as f:
            sys.stdout = f
            yield
    finally:
        # Ensure sys.stdout is restored in the event of an error
        sys.stdout = sys.__stdout__


with output_to_terminal():
    x = raw_input("> ")
print(x)