当从bash的bind调用时,为什么脚本不接受stdin上的输入?

时间:2013-06-04 22:49:43

标签: bash bind stdin tty stty

我编写了许多bash / bind工具来简化命令行的存在,并且最近想要使这些工具中的一个具有交互性。如果我尝试从其中一个脚本中的stdin读取,则执行会在读取时锁定。我的示例是在python中,但是当调用的脚本用ruby编写时,我看到了完全相同的行为:

~> cat tmp.py
import sys
sys.stdout.write(">>>")
sys.stdout.flush()
foo = sys.stdin.readline()
print "foo: %s" % foo,


~> python tmp.py
>>>yodeling yoda
foo: yodeling yoda

所以脚本有效。当我调用它时,我可以给它输入并打印我喂它的东西。

~> bind -x '"\eh":"echo yodeling yoda"'
[output deleted]

~> [Alt-H]
yodeling yoda

bind按预期工作。绑定键击调用该命令。我一直使用这些东西,但直到现在,我只调用了不需要stdin读取的脚本。

让我们将[Alt-H]绑定到脚本:

~> bind -x '"\eh":"python tmp.py"'
[output deleted]

现在我们配置为在绑定键击调用时从stdin读取脚本。按[Alt-H]启动脚本但没有输入任何类型的回显。即使击中[Crl-D]也不会结束它。退出的唯一方法是点击[Crl-C],在readline中杀死进程。 (sys.stdin.read()遭受同样的命运。)

~> [Alt-H]
>>>Traceback (most recent call last):
  File "tmp.py", line 7, in <module>
    foo = sys.stdin.readline()
KeyboardInterrupt

正如我在顶部提到的,我看到了与ruby相同的问题,所以我知道它与我正在使用的语言无关。 (我省略了脚本。)

~> bind -x '"\eh":"ruby tmp.rb"'
[Output deleted]

~> [Alt-H]
>>>tmp.rb:3:in `gets': Interrupt
    from tmp.rb:3

我查看了关于绑定的Bash参考手册条目,它没有说明对输入的限制。有什么想法吗?

编辑:

如果我在进程卡住时cat / proc / [PID] / fd / 0,我会看到脚本的输入正在显示。 (奇怪的是,相当数量的字符 - 似乎是随机的 - 未能出现在这里。只有在我输入几百个字节后才出现这种症状。)

找到this,描述终端如何以及何时在熟和原始模式之间切换。在提示开始时调用stty cookedstty echo,然后stty sanestty raw会触发新的级联问题;主要与如何处理绑定字符有关,但足以说它会破坏大多数alt绑定(以及更多)直到返回被击中几次。

2 个答案:

答案 0 :(得分:1)

最后,最好的答案证明是烹饪tty并手动打开echo,然后将tty设置恢复到我开始时的状态:

def _get_terminal_settings():                                                      
  proc = subprocess.Popen(['/bin/stty', '-g'], stdout=subprocess.PIPE)             
  settings = proc.communicate()[0]                                                 
  os.system('stty cooked echo')                                                    
  return settings                                                                  

def _set_terminal_settings(settings):                                              
  os.system('stty %s' % settings)    

...
...
settings = _get_terminal_settings()
user_input = sys.stdin.readline()
_set_terminal_settings(settings)
...
...

您应该能够以您选择的任何语言进行此操作。

如果您对为什么需要这种疯狂感到好奇,我建议您阅读我在上面添加的链接(在EDIT下)。文章没有涵盖任何足够的细节,但你至少比我开始时的理解更多。

答案 1 :(得分:0)

嗯,我的猜测是发生的事情是python脚本正在运行并在按下[Alt-H]时等待stdin的输入,但它的stdin范围与调用脚本的stdin范围不同。当你输入某些内容时,它会转到Bash脚本stdin,而不是pythons。也许找一种方法来“反向管道”或将stdin从bash shell转发到被调用脚本的stdin?

编辑:

好的,我研究了一下,看起来管道可能会起作用。这是一个非常丰富的链接: bash - redirect specific output from 2nd script back to stdin of 1st program?