带有回显的用户的 Python 提示和没有回显的密码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19661956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python prompt for user with echo and password without echo
提问by hyde
Following code prompts for user and password, when run in console:
在控制台中运行时,以下代码提示输入用户和密码:
import getpass
user = getpass.getpass("Username:")
passwd = getpass.getpass("Password for " + user + ":")
print "Got", user, passwd
The obvious problem with above is, user name is not echoed as it is typed.
上面的明显问题是,用户名在键入时没有回显。
Now getpass
documentationsays "On Unix it defaults to using /dev/tty before falling back to sys.stdin and sys.stderr."
现在getpass
文档说“在 Unix 上它默认使用 /dev/tty,然后再回到 sys.stdin 和 sys.stderr。”
Question:How to ask for both username and password, so that they are read from same source, and username is echoed normally, while password is not?
问题:如何同时要求用户名和密码,以便它们从同一来源读取,并且用户名正常回显,而密码不是?
采纳答案by Ken Pronovici
There is another alternative, which I found documented here. Detect whether the input stream is a TTY, and change your input method based on that information.
还有另一种选择,我在此处找到了记录。检测输入流是否为 TTY,并根据该信息更改您的输入法。
I used something like this:
我使用了这样的东西:
#!/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)
This works fine from a terminal:
这在终端上工作正常:
bash> ./mytest.py
Enter credentials
Username: one
Password:
Username: [one], password [two]
for piped input:
对于管道输入:
bash> echo "one
> two" | ./mytest.py
Username: [one], password [two]
for input from a file:
对于来自文件的输入:
bash> echo "one" > input
bash> echo "two" >> input
bash> ./mytest.py < input
Username: [one], password [two]
and also for a heredoc:
还有一个heredoc:
bash> ./mytest.py << EOF
> one
> two
> EOF
Username: [one], password [two]
Personally, that covers all of my needs.
就个人而言,这涵盖了我的所有需求。
回答by falsetru
回答by Ernst
try this:
尝试这个:
user = raw_input("Username:")
回答by Ernst
回答by JojOatXGME
It would be possible to use raw_input
(input
in Python 3) but as already mentioned in the question, getpass
is using /dev/tty before falling back to sys.stdin and sys.stderr. This means that in some situations getpass
and raw_input
is using different sources.
可以使用raw_input
(input
在 Python 3 中),但正如问题中已经提到的,getpass
在回退到 sys.stdin 和 sys.stderr 之前使用 /dev/tty。这意味着,在某些情况下getpass
,并raw_input
使用不同的来源。
On linux, you might see the difference by executing the application with the following command:
在 linux 上,通过使用以下命令执行应用程序,您可能会看到不同之处:
my_app.py < /path/to/some/file
The function raw_input
would read from the file while getpass
would still use the terminal. Even if it is not documented explicitly, the same is happening on Windows.
该函数raw_input
将从文件中读取,同时getpass
仍将使用终端。即使没有明确记录,Windows 上也会发生同样的情况。
I have not found a function that is doing something like getpass
without hiding the input. I think you have to implement it yourself or search for a library which is doing it. You can look at the current implementation of getpass
in Python 3and in Python 2.7to get some inspiration.
我还没有找到一个可以在getpass
不隐藏输入的情况下执行类似操作的函数。我认为您必须自己实现它或搜索正在执行它的库。您可以查看getpass
Python 3和Python 2.7中的当前实现以获得一些灵感。
I wrote an exmaple below. Basically, I used the implementation of Python 3 and removed everything that is related to hiding the input. Then, I made some changes to support Python 2.
我在下面写了一个例子。基本上,我使用了 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 == '##代码##3':
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
I tested my implementation with Python 2.7 on Windows and with Python 2.7 and 3.5 on Arch Linux.
我在 Windows 上使用 Python 2.7 以及在 Arch Linux 上使用 Python 2.7 和 3.5 测试了我的实现。