コマンドラインの存在を簡素化するために書いた多くの bash/bind ツールがあり、最近、これらのツールの 1 つをインタラクティブにしたいと考えています。これらのスクリプトのいずれかで 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 リファレンス マニュアルのエントリに目を通しましたが、入力の制限については何も述べていません。何かご意見は?
編集:
プロセスがスタックしている間に /proc/[PID]/fd/0 を cat すると、スクリプトの入力が表示されます。(奇妙なことに、ランダムに見えるかなりの数の文字がここに表示されません。この症状は、数百バイトの入力を行った後にのみ表示されます。)
thisを見つけました。これは、端末がクック モードと生モードを切り替える方法とタイミングの説明です。プロンプトの開始時に呼び出しstty cooked
、その後またはその後に呼び出しを行うと、問題の新しいカスケードがトリガーされます。主にバインドされた文字の処理方法に関連していますが、return が数回ヒットするまで、ほとんどの alt バインディング (およびそれ以上) を破壊すると言えば十分です。stty echo
stty sane
stty raw