When I run the command
python3 ./db.py 'blah blah blah' > output.html
The text "Enter your name: Enter your password:" appears in output.html. I do not want this to be there. It's accepting username and password but it isn't prompting the command line with "Enter your name". Any idea how I fix this?
This is the code I'm running:
import psycopg2
import sys
name = input("Enter your name: ")
passwd = input("Enter your password: ")
You could try redirecting your input calls to stderr. I recommend using contextlib so that all calls are redirected without having to specify file= every time. Here's a minimal example:
import contextlib
import sys
name, passwd = None, None
with contextlib.redirect_stdout(sys.stderr):
print("This does not appear in stdout.")
name = input("Please enter your name: ")
passwd = input("Please enter your password: ")
print("This still appears in stdout.")
print(f"name = {name}")
print(f"pass = {passwd}")
And when running:
$ python ./temp.py > temp-out.txt
This does not appear in stdout.
Please enter your name: Matt
Please enter your password: abc
$ cat ./temp-out.txt
This still appears in stdout.
name = Matt
pass = abc
Per my comment, however, I would suggest doing the writing in your actual Python. Try passing the desired output filename as a parameter/argument to the script.
When you use the input(prompt) function, the contents of prompt will be sent to standard output. That's in the documentation for input():
input?
Signature: input(prompt=None, /)
Docstring:
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a
trailing newline before reading input.
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
On *nix systems, readline is used if available.
Type: builtin_function_or_method
If you wish the result to be written to a file, you should do that in the code itself, rather than redirecting stdout to a file.
with open(filename, 'w') as file:
file.write(name+'\n')
file.write(passwd+'\n')
Just use stderr instead of stdout:
print("Enter your password: ", file=sys.stderr, flush=True)
password = input()
This way you'll have both prompt and clean output redirected to a file.
Related
I have a python script that asks at the beginning for user to enter a password, simply like this:
password = input()
in my bash script I have:
echo -n "password: "
read -s password
printf "$password" | python my_script.py
this works fine but I have a condition that if user enters the password incorrectly, the script prompts him to type the password again until he types the correct one, something like this:
while not login:
password = input()
login = check_correct(password)
I should be able to handle this in my bash script but I'm not sure how, I tried using yes command like this:
yes $(read -s password) | python3 my_script.py
but this always sends, as expected, the same input to the script.
Does anyone have any idea how could I do this?
You can do something like:
while True:
resp = input('Enter your password')
if check_correct(resp):
break
else:
print('Invalid Password, please try again')
I'm using Python 2.7's raw_input to read from stdin.
I want to let the user change a given default string.
Code:
i = raw_input("Please enter name:")
Console:
Please enter name: Jack
The user should be presented with Jack but can change (backspace) it to something else.
The Please enter name: argument would be the prompt for raw_input and that part shouldn't be changeable by the user.
You could do:
i = raw_input("Please enter name[Jack]:") or "Jack"
This way, if user just presses return without entering anything, "i" will be assigned "Jack".
Python2.7 get raw_input and set a default value:
Put this in a file called a.py:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return raw_input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
Run the program, it stops and presents the user with this:
el#defiant ~ $ python2.7 a.py
Caffeine is: an insecticide
The cursor is at the end, user presses backspace until 'an insecticide' is gone, types something else, then presses enter:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
Program finishes like this, final answer gets what the user typed:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
final answer: water soluable
Equivalent to above, but works in Python3:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
More info on what's going on here:
https://stackoverflow.com/a/2533142/445131
In dheerosaur's answer If user press Enter to select default value in reality it wont be saved as python considers it as '' string so Extending a bit on what dheerosaur.
default = "Jack"
user_input = raw_input("Please enter name: %s"%default + chr(8)*4)
if not user_input:
user_input = default
Fyi .. The ASCII value of backspace is 08
I only add this because you should write a simple function for reuse. Here is the one I wrote:
def default_input( message, defaultVal ):
if defaultVal:
return raw_input( "%s [%s]:" % (message,defaultVal) ) or defaultVal
else:
return raw_input( "%s " % (message) )
On platforms with readline, you can use the method described here: https://stackoverflow.com/a/2533142/1090657
On Windows, you can use the msvcrt module:
from msvcrt import getch, putch
def putstr(str):
for c in str:
putch(c)
def input(prompt, default=None):
putstr(prompt)
if default is None:
data = []
else:
data = list(default)
putstr(data)
while True:
c = getch()
if c in '\r\n':
break
elif c == '\003': # Ctrl-C
putstr('\r\n')
raise KeyboardInterrupt
elif c == '\b': # Backspace
if data:
putstr('\b \b') # Backspace and wipe the character cell
data.pop()
elif c in '\0\xe0': # Special keys
getch()
else:
putch(c)
data.append(c)
putstr('\r\n')
return ''.join(data)
Note that arrows keys don't work for the windows version, when it's used, nothing will happen.
For windows users with gitbash/msys2 or cygwin you can use it's built in readline through python subprocess. It is a sort of hack but works quite well and doesn't require any third party code. For personal tools this works really well.
Msys2 specific: If you want ctrl+c to immediately exit, you will need to run your program with
winpty python program.py
import subprocess
import shlex
def inputMsysOrCygwin(prompt = "", prefilled = ""):
"""Run your program with winpty python program.py if you want ctrl+c to behave properly while in subprocess"""
try:
bashCmd = "read -e -p {} -i {} bash_input; printf '%s' \"$bash_input\"".format(shlex.quote(prompt), shlex.quote(prefilled))
userInput = subprocess.check_output(["sh", "-c", bashCmd], encoding='utf-8')
return userInput
except FileNotFoundError:
raise FileNotFoundError("Invalid environment: inputMsysOrCygwin can only be run from bash where 'read' is available.")
userInput = ""
try:
#cygwin or msys2 shell
userInput = inputMsysOrCygwin("Prompt: ", "This is default text")
except FileNotFoundError:
#cmd or powershell context where bash and read are not available
userInput = input("Prompt [This is default text]: ") or "This is default text"
print("userInput={}".format(userInput))
Try this: raw_input("Please enter name: Jack" + chr(8)*4)
The ASCII value of backspace is 08.
So at my company they are making me use python 2.7 because of the product for a compatibility reason that I won't get into here.
So I am writing a program that connects to a device using SSH (a switch specifically) and I am able to actually access the device using SSH and this device is ping-able on my machine. The problem ? raw_input seems to not be taking it as a string. When I try input(), it gives me an invalid syntax error.
For the scripts I write, I usually use arparse and the user enters the IP address, username, and password through the terminal, but I want this script to not use argparse and to use input() or raw_input. All my SSH scripts work good except for this one, the only one using raw_input and input() instead of argparse
def runMain():
scriptName = os.path.basename(__file__)
print("The name of this script is: " + scriptName)
print("**************************************\n")
print("This script allows you to enable and disable ports on the SNET or SOOBM switches, have fun ! \n")
print("**************************************\n")
optionPrinter_switches_top()
user_input = raw_input("Make your selection") # This does not work if I change to input(), it exits out of the program
if user_input == 1:
print("You selected the SNET switch, lets proceed !")
deviceIP = input("Enter the IP address for this device") # I tried changing these to raw_input, I get a syntax issue
deviceUsername = input("Enter the username for this device")
devicePassword = input("Enter the password for this device")
confirm_ping = canPing(deviceIP) # This is a boolean function that works correctly in every script but this one.
if confirm_ping:
ssh_SNET = connectToSSH_SNET(deviceIP, deviceUsername, devicePassword)
else:
print("Sorry, that device is not even ping-able. Figure that issue out and retry the program...")
sys.exit(-1)
while True:
SNET_options()
user_choice_SNET = input("Please select an option")
switch_result = SNET_switch_func(user_choice_SNET)
if switch_result == "displayInterfaceBrief":
time.sleep(5)
displayInterfaceBrief_SNET(ssh_SNET)
elif switch_result == "enablePort":
time.sleep(5)
enablePort_SNET(ssh_SNET)
elif switch_result == "disablePort":
disablePort_SNET(ssh_SNET)
elif switch_result == "switchReboot":
reboot_SNET_switch(ssh_SNET)
else:
print("Exiting program now....")
sys.exit(-1)
Here are relevant issues:
user_input = raw_input("Make your selection") # This does not work if I change to input(), it exits out of the program
deviceIP = input("Enter the IP address for this device") # I tried changing these to raw_input, I get a syntax issue
deviceUsername = input("Enter the username for this device")
devicePassword = input("Enter the password for this device")
confirm_ping = canPing(deviceIP) # This is a boolean function that works correctly in every script but this one.
Conclusion ? There is an issue with input()/raw_input() . What is going on here and how can I fix this ? I can't use python 3.7 and it really is frustrating. Thanks for the help
Try changing if user_input == 1: to if int(user_input) == 1: as the input function takes an input in string format, by default.
And, if you want to use input() instead of raw_input() to take input from users in python 2.x, then you can try below code:
if hasattr(__builtins__, 'raw_input'):
input=raw_input
user_input = input("Enter a number: ")
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 documentation says "On Unix it defaults to using /dev/tty before falling back to sys.stdin and 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?
Why not just use raw_input for the username:
import getpass
user = raw_input("Username:")
passwd = getpass.getpass("Password for " + user + ":")
print("Got", user, passwd)
Demo:
Username:iCodez
Password for iCodez:
('Got', 'iCodez', 'secret')
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.
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:
bash> ./mytest.py << EOF
> one
> two
> EOF
Username: [one], password [two]
Personally, that covers all of my needs.
In Python 2.x, use raw_input (input in Python 3.x) instead of getpass.getpass for username.
user = raw_input("Username:")
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.
On linux, you might see the difference by executing the application with the following command:
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.
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 3 and in Python 2.7 to get some inspiration.
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.
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
I tested my implementation with Python 2.7 on Windows and with Python 2.7 and 3.5 on Arch Linux.
try this:
user = raw_input("Username:")
I'm using Python 2.7's raw_input to read from stdin.
I want to let the user change a given default string.
Code:
i = raw_input("Please enter name:")
Console:
Please enter name: Jack
The user should be presented with Jack but can change (backspace) it to something else.
The Please enter name: argument would be the prompt for raw_input and that part shouldn't be changeable by the user.
You could do:
i = raw_input("Please enter name[Jack]:") or "Jack"
This way, if user just presses return without entering anything, "i" will be assigned "Jack".
Python2.7 get raw_input and set a default value:
Put this in a file called a.py:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return raw_input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
Run the program, it stops and presents the user with this:
el#defiant ~ $ python2.7 a.py
Caffeine is: an insecticide
The cursor is at the end, user presses backspace until 'an insecticide' is gone, types something else, then presses enter:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
Program finishes like this, final answer gets what the user typed:
el#defiant ~ $ python2.7 a.py
Caffeine is: water soluable
final answer: water soluable
Equivalent to above, but works in Python3:
import readline
def rlinput(prompt, prefill=''):
readline.set_startup_hook(lambda: readline.insert_text(prefill))
try:
return input(prompt)
finally:
readline.set_startup_hook()
default_value = "an insecticide"
stuff = rlinput("Caffeine is: ", default_value)
print("final answer: " + stuff)
More info on what's going on here:
https://stackoverflow.com/a/2533142/445131
In dheerosaur's answer If user press Enter to select default value in reality it wont be saved as python considers it as '' string so Extending a bit on what dheerosaur.
default = "Jack"
user_input = raw_input("Please enter name: %s"%default + chr(8)*4)
if not user_input:
user_input = default
Fyi .. The ASCII value of backspace is 08
I only add this because you should write a simple function for reuse. Here is the one I wrote:
def default_input( message, defaultVal ):
if defaultVal:
return raw_input( "%s [%s]:" % (message,defaultVal) ) or defaultVal
else:
return raw_input( "%s " % (message) )
On platforms with readline, you can use the method described here: https://stackoverflow.com/a/2533142/1090657
On Windows, you can use the msvcrt module:
from msvcrt import getch, putch
def putstr(str):
for c in str:
putch(c)
def input(prompt, default=None):
putstr(prompt)
if default is None:
data = []
else:
data = list(default)
putstr(data)
while True:
c = getch()
if c in '\r\n':
break
elif c == '\003': # Ctrl-C
putstr('\r\n')
raise KeyboardInterrupt
elif c == '\b': # Backspace
if data:
putstr('\b \b') # Backspace and wipe the character cell
data.pop()
elif c in '\0\xe0': # Special keys
getch()
else:
putch(c)
data.append(c)
putstr('\r\n')
return ''.join(data)
Note that arrows keys don't work for the windows version, when it's used, nothing will happen.
For windows users with gitbash/msys2 or cygwin you can use it's built in readline through python subprocess. It is a sort of hack but works quite well and doesn't require any third party code. For personal tools this works really well.
Msys2 specific: If you want ctrl+c to immediately exit, you will need to run your program with
winpty python program.py
import subprocess
import shlex
def inputMsysOrCygwin(prompt = "", prefilled = ""):
"""Run your program with winpty python program.py if you want ctrl+c to behave properly while in subprocess"""
try:
bashCmd = "read -e -p {} -i {} bash_input; printf '%s' \"$bash_input\"".format(shlex.quote(prompt), shlex.quote(prefilled))
userInput = subprocess.check_output(["sh", "-c", bashCmd], encoding='utf-8')
return userInput
except FileNotFoundError:
raise FileNotFoundError("Invalid environment: inputMsysOrCygwin can only be run from bash where 'read' is available.")
userInput = ""
try:
#cygwin or msys2 shell
userInput = inputMsysOrCygwin("Prompt: ", "This is default text")
except FileNotFoundError:
#cmd or powershell context where bash and read are not available
userInput = input("Prompt [This is default text]: ") or "This is default text"
print("userInput={}".format(userInput))
Try this: raw_input("Please enter name: Jack" + chr(8)*4)
The ASCII value of backspace is 08.