Windows GitBash で Python・Node.js・Docker が上手く動かない場合は winpty を設定する
Windows GitBash にて、$ python
や $ node
コマンドを叩いて、プロンプト上で簡単なコードを動かしてみたかったのだが、どうもプロンプトの応答が戻ってこない。
また、$ docker
関連のコマンドを使うと、以下のようなエラーメッセージが返ってきた。
$ docker exec -it my-container bash
the input device is not a TTY.
If you are using mintty, try prefixing the command with 'winpty'
調べてみると、GitBash では、一部の対話式プロンプトを伴うコマンドは winpty
というコマンドを経由して実行してやらないと、上手くプロンプトが表示されないようだ。
目次
- まずは解決法だけ
winpty
を設定している/etc/profile.d/aliases.sh
- 以降は補足…
winpty
って何?- じゃあ全部のコマンドを
winpty
経由で実行したら? - 参考文献
まずは解決法だけ
ということで、
$ winpty python
$ winpty node
$ winpty docker exec -it my-container bash
という風に叩けば、正常に動いた。
winpty
を設定している /etc/profile.d/aliases.sh
でも、node
なんかはこんなことしなくても以前は使えていた気がするんだけどな…?と思い、もう少し調べてみると、原因が分かった。
以前、GitSDK および GitBash の起動速度を高速化するため、/etc/profile
をゴリゴリ書き換えたことがあった。
この中で、「特に呼び出す必要ねえだろ」と独断で省いてしまった /etc/profile.d/aliases.sh
の中で、winpty
を使うエイリアスを設定していたことが分かった。
case "$TERM" in
xterm*)
# The following programs are known to require a Win32 Console
# for interactive usage, therefore let's launch them through winpty
# when run inside `mintty`.
for name in node ipython php php5 psql python2.7
do
case "$(type -p "$name".exe 2>/dev/null)" in
''|/usr/bin/*) continue;;
esac
alias $name="winpty $name.exe"
done
;;
esac
こんな感じのコードが見えるかと思う。
for name in
の行を観ると、node
や python
、PostgreSQL の psql
などのコマンドが並んでおり、alias $name="winpty $name.exe"
と、winpty
を組み込んだエイリアスを定義しているのが分かるかと。
通常どおり /etc/profile.d/aliases.sh
を読み込んでいる環境なら、このファイルを編集し、for name in
の行の末尾に docker
を追加してやれば、docker
コマンドが正常に動くようになる。必要に応じて docker-compose
や docker-machine
なども入れておこう。
このファイルは使わない場合であれば、以下のようなエイリアス定義を ~/.bashrc
にでも入れておけば良い。やっていることは同じだ。
alias docker='winpty docker'
# Python や Node.js の場合
alias python='winpty python'
alias node='winpty node.exe'
自分の環境であればコレだけで事足りた。
以降は補足…
問題の直接的な解決はココまで。以降はココで使用した winpty
に関する調査記録。
winpty
って何?
ところで、ココで使っている winpty
とは何なのか。どうしてコレが一部のコマンドだけ必要で、最初から組み込んでおいてくれないのかを調べた。
TTY・PTS・PTY とは
winpty
を理解する前に、まず TTY (TeleTYpewriter) と PTS (Pseudo Terminal Slave)、PTY (Pseudo Terminal) を知っておく必要がありそうだ。
tty は、あるマシンの標準出力の接続先デバイスを示す。
例えば1つのサーバに2人が同時に ssh
している状態で、w
コマンドを叩くと、pts/0
、pts/1
といった TTY
列が見えるだろう。
この状態で SSH 接続しているそれぞれのユーザが tty
コマンドを叩くと、自分の TTY の仮想ファイルが /dev/pts/0
・/dev/pts/1
というように返ってくる。
tty
コマンドの結果が /dev/pts/0
なユーザのセッションにおいて、
$ echo 'TEST' > /dev/pts/0
と実行すると、自身のプロンプトに TEST
という文字列が出力される。さらに、ココで別の TTY を指定すると、
$ echo 'TEST' > /dev/pts/1
今度は /dev/pts/1
のユーザのプロンプトに、突然 TEST
の文字が出力される。
このように、TTY は /dev/pts/
配下の仮想ファイルで入出力を扱えるデバイスということになる。ココで登場する PTS は、仮想端末 (ターミナル) のスレーブ (接続先) ということ。接続先のサーバがマスターで、繋ぎに来ている2人のユーザのターミナルがスレーブという扱いになる。
ココまで来れば、PTY が「仮想端末」と呼ばれ、それが何を意味しているかも分かるだろう。今は「ターミナル」と呼ぶので「PTY は Pseudo Terminal の略」と表現するが、「じゃあその『Y』はどこから来たの?」というと、TTY にある「TYpewriter」の名残と同じで、「Pseudo (tele) TYpewriter」からの発展だと分かる。
pty stands for Pseudo-Terminal. Has anyone wondered, if tty is for Tele-Typewriter, why pty is not Pseudo-Typewriter?
- 参考 : Pseudoterminal - Wikipedia
- 英 Wikipedia では「Pseudoterminal」「Pseudotty」とも記載されている。
GitBash のベースとなる mintty
GitBash のベースとなる mintty (MinTTY) は、ターミナルエミュレータと呼ばれるソフトになる。いわゆる「黒い画面」を作るインターフェースでしかなく、コマンド群は Cygwin や MSYS が提供するという関係だ。GitSDK や GitBash インストーラは、MSYS と mintty、そして git
コマンドを統合した環境を構築・インストールしているワケである。
mintty のバグ?
というワケで、普段我々は、GitBash や GitSDK のフロントエンドとして、mintty というターミナルエミュレータを使っているのだが、この mintty のバグ (仕様?) により、一部のプロセスで対話モードのプロンプトが正常に表示できないようだ。
minttyはとても使い勝手が良い環境なのですが、「一部のアプリで対話モードが動作しない」といった問題点が存在します。
cygwinのterminalであるminttyっていうexeがネイティブのpython以外のpythonをたたくと固まるという既知のバグなんだそうです。
なので、mintty.exeの代わりにwinpty.exeというものを入れて、cygwinのterminalをラップしてやる必要がある。
本題・winpty
は何なのか
winpty
のリポジトリは以下にある。
ココを見ると、mintty と、そこから呼ばれた Windows 向けのプログラムとの間を仲介し、別プロセスとして立ち上がった winpty
が出力を上手く処理してくれるようだ。
mintty の対話プロンプトに関する既知の不具合に対し、橋渡しを行う仲介プログラムというワケだ。
じゃあ全部のコマンドを winpty
経由で実行したら?
winpty
を経由しないと、Python などのプログラムが動かないという問題は、いくつか Issues が挙げられている。
一番最初に挙げられた Issue はコレっぽい。
次に紹介する Issue の中で、「全部のプログラムを winpty
経由で実行させたらこんな問題起こらなくね?」と言われているが、次のような回答が付いている。
Why not just run everything through winpty?
@fletchowns measure it. No, seriously, measure the difference in startup time.
単純な話だが、全てのプロセスを winpty
に中継されると、それだけプロセス数が増加し、処理時間が余計にかかってしまうから、一部の有名なコマンドだけ抜き出して設定しているようだ。
また、以下の記事では次のように書かれている。
Otherwise, and probably even with such notice, there's going to be these kind of issues popping in continuously :).
I agree. It is of no use pointing out that we try to support Git here, and not a bazillion of interactive consoles for other software.
/etc/aliases.sh
でエイリアスを付与するやり方は問題を解決はできたが、今後似たような問題が起こるプログラムを見つけたらどんどん追記していかないといけなくなるよね? という問いに対し、「そうだけど、GitBash は Git をサポートするためのモノで、他のソフトを総合的にサポートするモノではない」という回答。
つまり、mintty 由来のバグの影響を受けるソフトがあるのは分かるが、Git For Windows はその全てに上手く対応するつもりはないよ、ということみたい。
そんなワケで、我々は GitBash を使う限りは、問題が起こるプログラムを見つけ次第、必要に応じて winpty
を挟むしかないということになる。とりあえず納得。
参考文献
winpty
を付与する件について
- Git for Windowsでdocker execをwinptyなしで実行する - Qiita
- git-bash for windows を快適にするためのいろいろ - Qiita
- WindowsでDocker Toolboxを使うために最低限やっておくこと - Qiita
- Windows の Git Bash から Docker や Docker Compose をうまく動かすための .bashrc – oki2a24
TTY・PTS・PTY
- ttyとptsとは – PAYFORWARD
- ttyについて ttyやptsってなんぞ? - それマグで!
- ttyとかptsとかについて確認してみる - Qiita
- tty - Wikipedia
- 擬似端末 - Wikipedia