Anscheinend ist dies fast ein Duplikat von "Bad pipe filedescriptor when reading from stdin in python - Stack Overflow"; Ich glaube jedoch, dass dieser Fall etwas komplizierter ist (und es ist nicht Windows-spezifisch, da die Schlussfolgerung dieses Threads war).Linux: Pipe in Python (ncurses) Skript, stdin und termios
Ich versuche gerade mit einem einfachen Skript in Python zu experimentieren: Ich würde gerne eine Eingabe für das Skript liefern - entweder über Befehlszeilenargumente; oder indem Sie eine Zeichenfolge an dieses Skript "pipen" - und das Skript diese Eingabezeichenfolge mit einer curses
Terminalschnittstelle anzeigen lässt.
Das vollständige Skript, hier testcurses.py
genannt, ist unten angegeben. Das Problem ist, dass, wenn ich die tatsächliche Rohrleitung versuche, das stdin zu versauen scheint, und das curses
Fenster nie zeigt. Hier ist eine Terminal-Ausgabe:
## CASE 1: THROUGH COMMAND LINE ARGUMENT (arg being stdin):
##
$ ./testcurses.py -
['-'] 1
stdout/stdin (obj): <open file '<stdout>', mode 'w' at 0xb77dc078> <open file '<stdin>', mode 'r' at 0xb77dc020>
stdout/stdin (fn): 1 0
env(TERM): xterm xterm
stdin_termios_attr [27906, 5, 1215, 35387, 15, 15, ['\x03', ... '\x00']]
stdout_termios_attr [27906, 5, 1215, 35387, 15, 15, ['\x03', ... '\x00']]
opening -
obj <open file '<stdin>', mode 'r' at 0xb77dc020>
TYPING blabla HERE
wr TYPING blabla HERE
at end
before curses TYPING blabla HERE
#
# AT THIS POINT:
# in this case, curses window is shown, with the text 'TYPING blabla HERE'
# ################
## CASE 2: THROUGH PIPE
##
## NOTE I get the same output, even if I try syntax as in SO1057638, like:
## python -c "print 'TYPING blabla HERE'" | python testcurses.py -
##
$ echo "TYPING blabla HERE" | ./testcurses.py -
['-'] 1
stdout/stdin (obj): <open file '<stdout>', mode 'w' at 0xb774a078> <open file '<stdin>', mode 'r' at 0xb774a020>
stdout/stdin (fn): 1 0
env(TERM): xterm xterm
stdin_termios_attr <class 'termios.error'>::(22, 'Invalid argument')
stdout_termios_attr [27906, 5, 1215, 35387, 15, 15, ['\x03', '\x1c', '\x7f', '\x15', '\x04', '\x00', '\x01', '\xff', '\x11', '\x13', '\x1a', '\xff', '\x12', '\x0f', '\x17', '\x16', '\xff', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']]
opening -
obj <open file '<stdin>', mode 'r' at 0xb774a020>
wr TYPING blabla HERE
at end
before curses TYPING blabla HERE
#
# AT THIS POINT:
# script simply exits, nothing is shown
# ################
Soweit ich sehen kann, ist die Frage: - wenn wir Rohrstränge in den Python-Skript, verlieren der Python-Skript den Verweis auf den Terminal als stdin
und Bekanntmachungen dass die ersetzte stdin
ist keine termios
Struktur mehr - und seit stdin
ist nicht mehr ein Terminal, curses.initscr()
beendet sofort ohne Rendering nichts.
Also, meine Frage ist - kurz: kann ich irgendwie erreichen, dass die Syntax echo "blabla" | ./testcurses.py -
in curses
die verrohrt Zeichenfolge zeigt endet? Genauer gesagt: Ist es möglich, einen Verweis auf die stdin
des aufrufenden Terminals aus einem Python-Skript abzurufen, selbst wenn dieses Skript "piped" wird?
Vielen Dank im Voraus für alle Hinweise,
Prost!
PS: das testcurses.py
Skript:
#!/usr/bin/env python
# http://www.tuxradar.com/content/code-project-build-ncurses-ui-python
# http://diveintopython.net/scripts_and_streams/stdin_stdout_stderr.html
# http://bytes.com/topic/python/answers/42283-curses-disable-readline-replace-stdin
#
# NOTE: press 'q' to exit curses - Ctrl-C will screw up yer terminal
# ./testcurses.py "blabla" # works fine (curseswin shows)
# ./testcurses.py - # works fine, (type, enter, curseswins shows):
# echo "blabla" | ./testcurses.py "sdsd" # fails to raise curses window
#
# NOTE: when without pipe: termios.tcgetattr(sys.__stdin__.fileno()): [27906, 5, 1215, 35387, 15, 15, ['\x03',
# NOTE: when with pipe | : termios.tcgetattr(sys.__stdin__.fileno()): termios.error: (22, 'Invalid argument')
import curses
import sys
import os
import atexit
import termios
def openAnything(source):
"""URI, filename, or string --> stream
http://diveintopython.net/xml_processing/index.html#kgp.divein
This function lets you define parsers that take any input source
(URL, pathname to local or network file, or actual data as a string)
and deal with it in a uniform manner. Returned object is guaranteed
to have all the basic stdio read methods (read, readline, readlines).
Just .close() the object when you're done with it.
"""
if hasattr(source, "read"):
return source
if source == '-':
import sys
return sys.stdin
# try to open with urllib (if source is http, ftp, or file URL)
import urllib
try:
return urllib.urlopen(source)
except (IOError, OSError):
pass
# try to open with native open function (if source is pathname)
try:
return open(source)
except (IOError, OSError):
pass
# treat source as string
import StringIO
return StringIO.StringIO(str(source))
def main(argv):
print argv, len(argv)
print "stdout/stdin (obj):", sys.__stdout__, sys.__stdin__
print "stdout/stdin (fn):", sys.__stdout__.fileno(), sys.__stdin__.fileno()
print "env(TERM):", os.environ.get('TERM'), os.environ.get("TERM", "unknown")
stdin_term_attr = 0
stdout_term_attr = 0
try:
stdin_term_attr = termios.tcgetattr(sys.__stdin__.fileno())
except:
stdin_term_attr = "%s::%s" % (sys.exc_info()[0], sys.exc_info()[1])
try:
stdout_term_attr = termios.tcgetattr(sys.__stdout__.fileno())
except:
stdout_term_attr = `sys.exc_info()[0]` + "::" + `sys.exc_info()[1]`
print "stdin_termios_attr", stdin_term_attr
print "stdout_termios_attr", stdout_term_attr
fname = ""
if len(argv):
fname = argv[0]
writetxt = "Python curses in action!"
if fname != "":
print "opening", fname
fobj = openAnything(fname)
print "obj", fobj
writetxt = fobj.readline(100) # max 100 chars read
print "wr", writetxt
fobj.close()
print "at end"
sys.stderr.write("before ")
print "curses", writetxt
try:
myscreen = curses.initscr()
#~ atexit.register(curses.endwin)
except:
print "Unexpected error:", sys.exc_info()[0]
sys.stderr.write("after initscr") # this won't show, even if curseswin runs fine
myscreen.border(0)
myscreen.addstr(12, 25, writetxt)
myscreen.refresh()
myscreen.getch()
#~ curses.endwin()
atexit.register(curses.endwin)
sys.stderr.write("after end") # this won't show, even if curseswin runs fine
# run the main function - with arguments passed to script:
if __name__ == "__main__":
main(sys.argv[1:])
sys.stderr.write("after main1") # these won't show either,
sys.stderr.write("after main2") # (.. even if curseswin runs fine ..)
Danke, mein Herr, für die prägnante - und funktionierende - Antwort! :) Ich benutze tatsächlich 'bash', da ich auf Ubuntu Lucid bin. Mein Beispiel, das mit Ihren Änderungen aktualisiert wurde, finden Sie unter [testcurses-stdin.py] (http://sdaaubckp.svn.sourceforge.net/viewvc/sdaaubckp/single-scripts/testcurses-stdin.py?revision=75&content- type = text% 2Fplain & pathrev = 75); und es sollte mit ''(echo" blabla "| ./testcurses-stdin.py -) aufgerufen werden 3 <& 0'' ... – sdaau
_PS: Ich muss zugeben, ich habe [I/O Umleitung] (http: //www.faqs.org/docs/abs/HTML/io-redirection.html) hunderte Male - auch bevor ich das gepostet habe - und es endet immer damit, mich zu verwirren; Ich hätte es wirklich schwer gehabt, die richtige Lösung herauszufinden. Da ich One-Liners sehr mag, ist die "hässliche Syntax auf der Kommandozeile" tatsächlich ** am meisten geschätzt - eines der Dinge, die ich nicht mag, ist die Ausführung von "exec 3" & 0 "vor dem Ausführen von etwas, das im Wesentlichen ein Einstrich ist. Nochmals vielen Dank für die Antwort, Frédéric - und Prost! – sdaau