Linux:管道进入Python(ncurses)脚本,stdin和termios

Linux:管道进入Python(ncurses)脚本,stdin和termios,第1张

概述显然这几乎是“Bad pipe filedescriptor when reading from stdin in python - Stack Overflow”的重复;但是,我认为这种情况稍微复杂一些(并且它不是Windows特定的,因为该线程的结论是).我目前正在尝试用Python编写一个简单的脚本:我想为脚本提供输入 - 通过命令行参数;或者通过“管

显然这几乎是“Bad pipe filedescriptor when reading from stdin in python – Stack Overflow”的重复;但是,我认为这种情况稍微复杂一些(并且它不是windows特定的,因为该线程的结论是).

我目前正在尝试用Python编写一个简单的脚本:我想为脚本提供输入 – 通过命令行参数;或者通过“管道”字符串到此脚本 – 并让脚本使用curses终端接口显示此输入字符串.

完整的脚本,这里称为testcurses.py,如下所示.问题是每当我尝试实际的管道时,这似乎搞乱了stdin,而curses窗口从未显示过.这是一个终端输出:

## CASE 1: THROUGH COMMAND liNE ARGUMENT (arg being stdin):##$./testcurses.py -['-'] 1stdout/stdin (obj): 

据我所知,问题是: – 每当我们将字符串传递给Python脚本时,Python脚本就会失去对终端的引用作为stdin,并注意到被替换的stdin不再是termios结构 – 并且因为stdin是不再是终端,curses.initscr()立即退出而不渲染任何东西.

所以,我的问题是 – 简而言之:我可以以某种方式实现,语法echo“blabla”| ./testcurses.py – 最终在curses中显示管道字符串?更具体地说:是否可以从Python脚本中检索对调用终端的stdin的引用,即使此脚本被“管道”到?

提前感谢任何指针,

干杯!

PS:testcurses.py脚本:

#!/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,# NOTE: when with pipe |   : termios.tcgetattr(sys.__stdin__.fileno()): termios.error: (22,'InvalID argument') import cursesimport sysimport osimport atexitimport termiosdef 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 ..)
最佳答案如果不涉及父进程,则无法完成此 *** 作.幸运的是,有一种方法可以使用I/O redirection获得bash:

$(echo "foo" | ./pipe.py) 3<&0

这会将foo管道传递到子shell中的pipe.py,并将stdin复制到文件描述符3.现在我们需要做的就是在python脚本中使用父进程的额外帮助(因为我们将继承fd 3):

#!/usr/bin/env pythonimport sys,osimport cursesoutput = sys.stdin.readline(100)# We're finished with stdin. Duplicate inherited fd 3,# which contains a duplicate of the parent process' stdin,# into our stdin,at the OS level (assigning os.fdopen(3)# to sys.stdin or sys.__stdin__ does not work).os.dup2(3,0)# Now curses can initialize.screen = curses.initscr()screen.border(0)screen.addstr(12,output)screen.refresh()screen.getch()curses.enDWin()

最后,您可以通过首先运行子shell来解决命令行上的丑陋语法:

$exec 3<&0  # spawn subshell$echo "foo" | ./pipe.py  # works$echo "bar" | ./pipe.py  # still works

如果你有bash,那就解决了你的问题. 总结

以上是内存溢出为你收集整理的Linux:管道进入Python(ncurses)脚本,stdin和termios全部内容,希望文章能够帮你解决Linux:管道进入Python(ncurses)脚本,stdin和termios所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1046719.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)