17

以下代码在控制台中运行时提示输入用户和密码:

import getpass

user = getpass.getpass("Username:")
passwd = getpass.getpass("Password for " + user + ":")

print "Got", user, passwd

上面的明显问题是,用户名在输入时没有回显。

现在getpass文档“在 Unix 上,它默认使用 /dev/tty,然后再回退到 sys.stdin 和 sys.stderr。”

问题:如何同时要求用户名和密码,以便从同一来源读取它们,并且用户名正常回显,而密码则不?

4

5 回答 5

15

为什么不只使用raw_input用户名:

import getpass

user = raw_input("Username:")
passwd = getpass.getpass("Password for " + user + ":")

print("Got", user, passwd)

演示:

Username:iCodez
Password for iCodez:
('Got', 'iCodez', 'secret')
于 2013-10-29T15:08:52.867 回答
12

还有另一种选择,我发现它记录在这里。检测输入流是否为 TTY,并根据该信息更改输入法。

我用过这样的东西:

#!/usr/bin/python

import sys
import getpass

if sys.stdin.isatty():
   print "Enter credentials"
   username = raw_input("Username: ")
   password = getpass.getpass("Password: ")
else:
   username = sys.stdin.readline().rstrip()
   password = sys.stdin.readline().rstrip()

print "Username: [%s], password [%s]" % (username, password)

这在终端上可以正常工作:

bash> ./mytest.py
Enter credentials
Username: one
Password:
Username: [one], password [two]

对于管道输入:

bash> echo "one
> two" | ./mytest.py
Username: [one], password [two]

对于来自文件的输入:

bash> echo "one" > input
bash> echo "two" >> input
bash> ./mytest.py < input
Username: [one], password [two]

还有一个heredoc:

bash> ./mytest.py << EOF
> one
> two
> EOF
Username: [one], password [two]

就个人而言,这涵盖了我的所有需求。

于 2017-02-22T22:18:52.977 回答
11

在 Python 2.x 中,使用raw_input(input在 Python 3.x 中) 代替getpass.getpass用户名。

user = raw_input("Username:")
于 2013-10-29T15:07:59.550 回答
5

可以使用raw_inputinput在 Python 3 中),但正如问题中已经提到的,getpass在回退到 sys.stdin 和 sys.stderr 之前使用 /dev/tty。这意味着在某些情况下getpassraw_input正在使用不同的来源。

在 linux 上,您可能会通过使用以下命令执行应用程序来看到差异:

my_app.py < /path/to/some/file

该函数raw_input将从文件中读取,同时getpass仍会使用终端。即使没有明确记录,Windows 上也会发生同样的情况。


我还没有找到一个在getpass不隐藏输入的情况下执行类似操作的函数。我认为您必须自己实现它或搜索正在执行它的库。您可以查看getpass Python 3Python 2.7中的当前实现以获得一些灵感。

我在下面写了一个例子。基本上,我使用了 Python 3 的实现并删除了与隐藏输入相关的所有内容。然后,我做了一些更改以支持 Python 2。

def _raw_input(prompt, fin, fout):
    if prompt:
        try:
            fout.write(prompt)
        except UnicodeEncodeError:
            # Replace characters that are not supported by the terminal
            prompt = prompt.encode(fout.encoding, 'replace')
            prompt = prompt.decode(fout.encoding)
            fout.write(prompt)
        fout.flush()

    line = fin.readline()
    return line[:-1] if line[-1] == '\n' else line

def _ttyinput_unix(prompt):
    try:
        fd = os.open("/dev/tty", os.O_RDWR, os.O_NOCTTY)
        if sys.version_info < (3, 0):
            with os.fdopen(fd, 'w+', 1) as tty:
                return _raw_input(prompt, tty, tty)
        with io.FileIO(fd, 'w+') as tty:
            with io.TextIOWrapper(tty) as wrapper:
                return _raw_input(prompt, wrapper, wrapper)
    except (OSError, AttributeError) as e:
        return _raw_input(prompt, sys.stdin, sys.stderr)

def _ttyinput_win(prompt):
    if sys.stdin is not sys.__stdin__:
        # I don't know why getpass is doing this.
        return _raw_input(prompt, sys.stdin, sys.stderr)

    if sys.version_info >= (3, 0):
        getch = msvcrt.getwch
        putch = msvcrt.putwch
    else:
        getch = msvcrt.getch
        putch = msvcrt.putch

    for c in prompt:
        putch(c)

    password = ""
    while True:
        c = getch()
        if c == '\r' or c == '\n':
            break
        if c == '\003':
            raise KeyboardInterrupt
        if c == '\b':
            if len(password) > 0:
                password = password[:-1]
                for x in "\b \b":
                    putch(x)
        else:
            password += c
            putch(c)
    putch('\r')
    putch('\n')

    return password

try:
    import msvcrt
    ttyinput = _ttyinput_win
except ImportError:
    ttyinput = _ttyinput_unix

我在 Windows 上使用 Python 2.7 以及在 Arch Linux 上使用 Python 2.7 和 3.5 测试了我的实现。

于 2016-12-11T04:45:17.787 回答
0

尝试这个:

user = raw_input("Username:")
于 2013-10-29T15:08:29.707 回答