开发者

Pipes and prompts in Python CLI scripts

Is it possible to combine piped input and TTY prompts in Python CLI scripts? E.g., running this:

import sys

piped_text = None

if not sys.stdin.isatty():
    piped_text = sys.stdin.read()

user_in = raw_input('Enter something: ')

if piped_text:
    sys.stdout.write(piped_text)

sys.stdout.write(user_in + '\n')  

Produces the following output:

~: python mrprompt.py
Enter something: something
something
~: echo foo | python mrprompt.py
Enter something: Traceback (most recent call last):
  File "mrprompt.py", line 9, in <module>
    user_in = raw_input('Enter something: ')
EOFError: EOF when reading a line

When the output I'm looking for is this:

~: python mrprompt.py
Enter something: something
something
~: echo foo | python mrprompt.py
Enter something: something
foo
something

I guess, worded differently, is it possible for a 开发者_StackOverflow社区subshell to know the tty of its parent shell? Is it possible, in Python, to interact a parent shell's tty? I use bash inside of GNU Screen (therefore, reading the 'SSH_TTY' environment variable is not a viable option).


This works, more or less:

#!/usr/bin/python

import sys

saved_stdin = sys.stdin
sys.stdin = open('/dev/tty', 'r')
result = raw_input('Enter something: ')
sys.stdout.write('Got: ' + result + '\n')
sys.stdin = saved_stdin
result2 = sys.stdin.read()
sys.stdout.write('Also got: ' + result2)

Save as foo.py and try echo goodbye | ./foo.py

Of course, /dev/tty only exists on Unix. And if you run it in a process with no controlling terminal, the open() will probably fail...


You can detect whether or not your stdin is coming from a pipe, as you are with sys.stdin.isatty. You're getting the EOF because you read all the input from with the stdin.read() and then you try to read some more with the raw_input() command.

What you can't do is both pipe input and do inter-active input. If you're piping input in, there is no other stdin for raw_input to work against. The only stdin is the one coming from the file.

What you need to do is offer an optional way to have the appropriate part of your script read input from a file, with a switch like

--input=file.txt

and then provide interactive prompts for the other parts.


It is possible to accept both piped input and user input in the same program.

The easiest way to handle this is with the subprocess module. You would be executing the program from within your Python program. The arguments for it allow you to setup pipes to and/or from the program you are executing.

It is simple. It is standard. It works well.

The same is true for accepting a file through program arguments. It is simple. It is standard. It works well. As an added benefit, in Windows CMD.EXE/COMMAND.COM automatically uses temporary files for pipes. You get no benefit for doing anything more complicated due to DOS/Windows not supporting true pipes.

I know the command-line mysql client code accepts a password from the user before processing piped-in input. The Linux (and probably Mac OS X) solution to this is probably similar to what Nemo posted. If that's the behavior you really want, and you don't care about Windows, that's the solution to use. (For Windows, you'd need to use something like the wconio package. -- http://newcenturycomputers.net/projects/wconio.html)

It is possible to have user-input and accept piped output going to another program. There are three standard file-handles: stdin, stdout, and stderr. You can write to stderr even when stdout is being redirected to a file.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜