Edit: My main question is, is there some way for a subprocess's stdout to be non-exclusively piped into the process's stdin. Non-exclusively so that the keyboard still works. Both need to go into a raw_input prompt.
Context: I'm creating a python program that allows people who've bought tickets with qr codes entry at an event. The main part of the program is a raw_input() on loop that searches through a csv for a guest's name, email address or the unique hash that is embedded in the QR codes. I am trying to use zbarcam to scan in the unique hash. This almost works:
from subprocess import Popen, PIPE
p = Popen(["/cygdrive/c/Program Files (x86)/ZBar/bin/zbarcam", "--raw"], stdout=PIPE)
That is, the QR code is scanned and the ticket hash pops up at the prompt so I can hit enter and have it search. The problem is zbarcam adds a newline so when I hit enter, it searches for a newline and returns everything in the csv. I can't find any way to strip the newline after the zbarcam output is piped to stdout (which enters into raw_input). Come to think of it, I can't even backspace or remove the newline using the keyboard. Do you know how to do that? I've done that sort of thing before, usually by copy-pasting an extra newline.
I added this line after the above ones:
sys.stdin = p.stdout
and the QR code's newline was interpretd as an "enter" and the search process started, but it just took away my ability to type in a search term. Is there some way to have stdin routed to both of those?
Is there some other way I can get user input from a keyboard and from zbarcam?
Thanks in advance! I hope I sound coherant--been a long day.
Edit: if anyone wants to bash themselves in the head with this profoundly hacked-together code, they can have a look here https://github.com/rtwolf/qr-event-entry/blob/master/pulp_entry.py
Related
I am trying to run following code
process = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE)
while process.poll() is None:
stdoutput = process.stdout.readline()
print(stdoutput.decode())
if '(Y/N)' in stdoutput.decode():
process.communicate(input=b'Y\n')
this cmd argument runs for a few minutes after which it prompts for a confirmation, but the process.communicate is not working, neither is process.stdin.write()
How do I send input string 'Y' to this running process when it prompts for confirmation
Per the doc on Popen.communicate(input=None, timeout=None):
Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE.
Please try that, and if it's not sufficient, do indicate what the symptom is.
On top of the answer from #Jerry101, if the subprocess that you are calling is a python script that uses the input(), be aware that as documented:
If the prompt argument is present, it is written to standard output without a trailing newline.
Thus if you perform readline() as in process.stdout.readline(), it would hang there waiting for the new line \n character as documented:
f.readline() reads a single line from the file; a newline character (\n) is left at the end of the string
A quick fix is append the newline \n when requesting the input() e.g. input("(Y/N)\n") instead of just input("(Y/N)").
Related question:
Python subprocess stdout doesn't capture input prompt
I have a code with function sys.stdin.readlines().
What is the difference between the above one and sys.stdin.buffer.readlines()?.
What exactly do they do ?
If they read lines from command line,how to stop reading lines at a certain instant and proceed to flow through the program?
1) sys.stdin is a TextIOWrapper, its purpose is to read text from stdin. The resulting strings will be actual strs. sys.stdin.buffer is a BufferedReader. The lines you get from this will be byte strings
2) They read all the lines from stdin until hitting eof or they hit the limit you give them
3) If you're trying to read a single line, you can use .readline() (note: no s). Otherwise, when interacting with the program on the command line, you'd have to give it the EOF signal (Ctrl+D on *nix)
Is there a reason you are doing this rather than just calling input() to get one text line at a time from stdin?
From the docs
sys.stdin
sys.stdout
sys.stderr
File objects corresponding to the interpreter’s standard input, output and error streams. stdin is used for all interpreter input except for scripts but including calls to input(). stdout is used for the output of print() and expression statements and for the prompts of input(). The interpreter’s own prompts and (almost all of) its error messages go to stderr. stdout and stderr needn’t be built-in file objects: any object is acceptable as long as it has a write() method that takes a string argument. (Changing these objects doesn’t affect the standard I/O streams of processes executed by os.popen(), os.system() or the exec*() family of functions in the os module.)
Note: The standard streams are in text mode by default. To write or read binary data to these, use the underlying binary buffer. For example, to write bytes to stdout, use sys.stdout.buffer.write(b'abc').
So, sys.stdin.readlines() reads everything that was passed to stdin and separates the contents so lines are formed (you get a list as a result).
sys.stdin.buffer.readlines() does the same, but for buffer of stdin. I'd suggest to use the first method as the buffer may be empty while stdin may contain some data.
If you want to stop at some moment, then use readline() to read only one line at a time.
Can someone explain stdin and stdout? I don't understand what is the difference between using these two objects for user input and output as opposed to print and raw_input. Perhaps there is some vital information I am missing. Can anyone explain?
stdin and stdout are the streams for your operating system's standard input and output.
You use them to read and write data from your operating system's std input (usually keyboard) and output (your screen, the python console, or such).
print is simply a function which writes to the operting system's stdout and adds a newline to the end.
There are more features in print than just this, but that's the basic idea.
# Simplified print implementation
def print(value, end='\n'):
stdout.write(value)
stdout.write(end)
stdin and stdout are stream representations of the standard in- and output that your OS supplies Python with.
You can do almost everything you can do with a file on these, so for many applications, they are far more useful than eg. print, which adds linebreaks etc.
Is there any easy way to handle multiple lines user input in command-line Python application?
I was looking for an answer without any result, because I don't want to:
read data from a file (I know, it's the easiest way);
create any GUI (let's stay with just a command line, OK?);
load text line by line (it should pasted at once, not typed and not pasted line by line);
work with each of lines separately (I'd like to have whole text as a string).
What I would like to achieve is to allow user pasting whole text (containing multiple lines) and capture the input as one string in entirely command-line tool. Is it possible in Python?
It would be great, if the solution worked both in Linux and Windows environments (I've heard that e.g. some solutions may cause problems due to the way cmd.exe works).
import sys
text = sys.stdin.read()
After pasting, you have to tell python that there is no more input by sending an end-of-file control character (ctrl+D in Linux, ctrl+Z followed by enter in Windows).
This method also works with pipes. If the above script is called paste.py, you can do
$ echo "hello" | python paste.py
and text will be equal to "hello\n". It's the same in windows:
C:\Python27>dir | python paste.py
The above command will save the output of dir to the text variable. There is no need to manually type an end-of-file character when the input is provided using pipes -- python will be notified automatically when the program creating the input has completed.
You could get the text from clipboard without any additional actions which raw_input() requires from a user to paste the multiline text:
import Tkinter
root = Tkinter.Tk()
root.withdraw()
text = root.clipboard_get()
root.destroy()
See also How do I copy a string to the clipboard on Windows using Python?
Use :
input = raw_input("Enter text")
These gets in input as a string all the input. So if you paste a whole text, all of it will be in the input variable.
EDIT: Apparently, this works only with Python Shell on Windows.
I am using pexpect with python to create a program that allows a user to interact with a FORTRAN program through a website. From the FORTRAN program I am receive the error:
open: Permission denied apparent state: unit 4 named subsat.out.55 last format: list io lately writing sequential formatted external IO 55
when I attempt to:
p = pexpect.spawn(myFortranProgram,[],5)
p.logfile_read = sys.stdout
p.expect("(.*)")
p.sendline("55")
From what I understand, I am likely sending the 55 to the wrong input unit. How do I correctly send input to a FORTRAN program using pexpect in Python?
Thank You.
Edit: When p.sendline's parameter is empty (e.g. p.sendline()) or only contains spaces, the program proceeds as expected. In sending non-space values to a FORTRAN program, do I need to specify the input format somehow?
The pexpect module is something I'd not used before, but could be useful to me, so I tried this.
Edit:
I've not been able to duplicate the error you're reporting. Looking at this error leads me to believe that it has something to do with reading from a file, which may be a result of other issues. From what I've seen, this isn't what pexpect is designed to handle directly; however, you may be able to make it work with a pipe, like the example in my original answer, below.
I'm having no problem sending data to Fortran's I/O stream 5 (stdin). I created a Fortran program called regurgitate which issues a " Your entry? " prompt, then gets a line of input from the user on I/O stream 5, then prints it back out. The following code works with that program:
import pexpect
child = pexpect.spawn('./regurgitate')
child.setecho(False)
ndx = child.expect('.*Your entry?.*')
child.sendline('42')
child.expect([pexpect.EOF])
print child.before
child.close()
The output is simply:
42
Exactly what I expected. However, if my Fortran program says something different (such as "Your input?"), the pexpect just hangs or times out.
Original suggestion:
Maybe this pexpect.run() sample will help you. At least it seems to run my regurgitate program (a simple Fortran program that accepts an input and then prints it out):
import pexpect
out = pexpect.run('/bin/bash -c "/bin/cat forty-two | ./regurgitate"')
print out
The output was:
Your entry?
42
Where regurgitate prints out a "Your entry?" prompt and the forty-two file contains "42" (without quotes in both cases).