前回に引き続き
次はscreen -X
でコマンドを送るときのついての話。
msgminwaitを0に
msgminwait
はステータスラインにメッセージを送る様なコマンドを一度送り、
次のコマンドが来て、それもステータスラインにメッセージを送るコマンドだった場合、
直ぐに次のコマンドに行くのではなくmsgminwait
秒だけ待ってくれる、
という時間を設定します
1。
man screen:
msgminwait sec
Defines the time screen delays a new message when one message is cur-
rently displayed. The default is 1 second.
通常のscreen内のコマンドであれば一つ一つ実行していくだけで問題が無いようなんですが、
screen -X
を使ったスクリプトをキーバインドで呼ぶようなときには
問題が起こるようです。
msgminwait
が0でない状態で(デフォルトは1)screen -X
を大量に含む
スクリプトを呼ぶと(特に領域を分割したりするちょっと時間がかかるような場合(?))
/tmp/uscreens/S-USER/xxxxx.ttys002.yyy: connect: Connection refused
とscreen -Qのところでも出てきた エラーが出ます(もしかしたらこの部分はmsgminwaitの問題かも)。
これをmsgminwait
を0に設定すると消えてくれました。
なので、とりあえずmsgminwait
は.screenrc
内で
msgminwait 0
しておいた方が良さそうです(下に書いてあるように何故か上手く機能しないので いずれにしろ0で無い意味がないので)。
execをキーバインド内に入れる場合
次の様なキーバインドを考えます。
bind a eval 'exec /bin/sh -c "~/set_win.sh"' 'split' 'focus' 'select 1'
やってることは
set_win.sh
を実行(ファイルは$HOME/
へ設置)- 画面を横分割
- 次の領域に移る
$win
番のウィンドウを表示
ここで、set_win.sh
の中身は
1 2 |
|
と、screen
コマンドで新しいウィンドウを作るだけのコマンド
2。
もともとウィンドウ0だけがあって、これによってウィンドウ1ができる状態を考えます。
それからCtrl-a aとして上のキーバインドを実行。
そうすると、2つ目の領域がWindow 1になって欲しいのですが そうなりません。
画面は分割されてWindow 1は作られて、さらにフォーカスも 2番めの領域に行っていますが、2番めの領域は空のママ。
ただ、新しくウィンドウを作るコマンドも、分割コマンドなども実行はされているようなので、
試しに、もともと、ウィンドウ0,1が両方ある状態で、上のコマンドを実行すると、 2個めの領域に正しくウィンドウ1が表示されました。 (この時、もちろん、ウィンドウ2が新たに出来ています。)
どうも、キーバインドでexec
を使ってスクリプトを呼ぶと、
その操作の終了を正しく待たずに次へ行ってしまう様です。
なので、最初の場合、screen
コマンドが終わる前にselect
仕様として無い、という状態。
これを、
bind a eval 'screen' 'split' 'focus' 'select 1'
の様にすべてscreenコマンドで収めると、 2つに分解され、上も下もWindow 1になります。
これは、最初のscreen
コマンドで新しくWindowを作るときに新しいウィンドウ(Window 1)
に移動し、そこでsplit
して新たな領域に移動してそこでもWindow 1を出す、
ということをしてるので正しいです。
(execの中だとサブシェルになるので(?)screen
しても新しいウィンドウを作るだけで
そちらに移動はしないみたいです。)
逆に、
1 2 3 4 5 |
|
として、
bind a eval 'exec /bin/sh -c "~/set_win.sh"'
の様に、全部スクリプトの中だけで行うようにすると、 分割され、かつ、最初の領域にはウィンドウ1が、 次の領域にはウィンドウ2が来てそちらにフォーカスが、 という感じになり、正しく動いているように見えます。
これをさらに、
1 2 |
|
1 2 3 4 |
|
と2つのスクリプトに分けて、
bind a eval 'exec /bin/sh -c "~/set_win.sh"' 'exec /bin/sh -c "~/set_win2.sh"'
と、順番に呼んであげると、
Filter running: ... /bin/sh -c "~/set_win.sh"
の様な表示がステータスラインに表れて、画面が分割されません。
set_win.sh
の方は実行されているようで、新しいウィンドウはできていますが、
set_win2.sh
の方は実行されてないようです。
この場合は、最初の例と同じように最初のスクリプトの終了を待たずに
2個めのスクリプトの実行にかかっているようですが、
その時に、中でscreen -X
を使うに、前のスクリプトでのアクセスが行われているために
拒否されて失敗した状態、何だと思います。
screen -X screen
上ではスクリプト内でscreen
コマンドをうつことで新しいウィンドウを作っていますが、
これだと少しおかしな動作をします。
screenを起動した中でコマンドラインからscreen
コマンドを打つと
新たにセッションが始まるのではなく、そのセッション内で新しいウインドウが出来るわけですが、
ちょっと使っていたらCtrl-hが左一文字消す、
という動作から、左側全部消す(Ctrl-uみたいな動作)%
になってしまいました。
この辺よくわからなかったんですが、
screen
の代わりに、screen -X screen
と、-X
で
中に直接screen内のscreen
コマンドを実行(コチラは常に新しいウィンドウを作る)
問題なく使えました。
screen -X後の待ち時間
追記: 2014/05/27
screen -Q
が使えないので、ウィンドウが存在しているかどうかについて、
screen -X register . test
screen -p 0 -Q writebuf ~/test_file
if [ -f ~/test_file ];then
echo window 0 exists!
fi
みたいな事をして、screen -p 0 -X
を使い、
特定のウィンドウを指定してコマンドを送り、
存在していればwritebuf
によってレジストリの書き出しによりファイルを作成し、
存在しなければこのコマンドが実行されない、ということを使っています。
この時、MacやWindowsで使うときには問題なかったのですが、 一部のLinuxで上手く作用しない時がありました。
どうやら、screen -X
コマンドが実行されてる間にファイルを先に
チェックしに行ってしまってファイルが出来てない、と勘違いしてしまうようです。
(screen -X
はscreen内にコマンドを送るだけで、中のコマンドが終了するしないにかかわらず、
シェルスクリプトの中ではコマンドを送った段階で次に行ってしまう様。)
screen -p...
の後に、sleep 1
を入れるときちんと動きましたが、
1秒待つのはだるいので
3、
コマンドを待つのをチェックするために
screen -X register . test
screen -p 0 -Q writebuf ~/test_file
while [ 1 ];do
if ! ps -u$USER |grep "screen -p $i -X writebuf $test_file";then
break
fi
done
if [ -f ~/test_file ];then
echo window 0 exists!
fi
こんな感じでやってみたらうまくいきました。
ただ、上のループの中にecho
とか入れてチェックしてみると、
このループは毎回1回しか呼ばれてないし、
よく考えてみると、screen -X
自体のコマンドは終わってるはずなので
ps
で引っかかるわけがありません。
ただ、上手く行ってるので、試しに、
screen -p 0 -Q writebuf ~/test_file
ps >/dev/null
if [ -f ~/test_file ];then
みたいにしても上手く行きました。
つまり、単にps
にちょっと時間がかかってその分で十分な待ち時間が出来ただけのようです。
usleep
が無い場合もあるので、
ちょっとあれですが適当なコマンドで、ということで、最終的には
状態の依存性が少なそうな
screen -p 0 -Q writebuf ~/test_file
date >/dev/null
if [ -f ~/test_file ];then
とdate
を使うことに。これで今のところ使ってる環境では全部大丈夫で、
それほど遅延も気になりません。
ちなみに、echo
も使ってみましたがこちらだと全く遅延を産まないのか
入れない場合と変わりませんでした。
追記ここまで
まとめ
screen -X
を使う様なスクリプトをキーバインドに割り当てたい場合は
msgminwait 0
にしておく。- どうしても普段は0にしたくないならスクリプトの最初と最後に
screen -X msgminwait 0
とscreen -X msgminwait 1
(もしくは設定したい時間) とかにすれば良いかも。
- どうしても普段は0にしたくないならスクリプトの最初と最後に
- キーバインドにはスクリプト一つだけを設定し、一つのキーバインドで複数のスクリプトは実行しない。
- スクリプト内で
screen
単体は使わない。新しいウィンドウを作りたいときはscreen -X screen
をする。
ということで。
-
ただ、今ちょっと試してみたらなんか上手く設定できないみたいで
msgminwait 5
と設定しても(msgwait 5
も設定)bind a eval 'echo aaa' 'echo bbb'
みたいなことしても直ぐに
bbb
が表示されるしbind b eval 'echo ccc' 'echo ddd'
として、
a
を実行して5秒以内にb
を実行してもすぐddd
が表示されます。何か変わったのかscreenのバグなのか何か自分の設定がおかしいのか。 前に色々設定をいじろうとした時に試してみた時は きちんと働いてた様な気もするのですが。。。
ただし、上に書いてあることに関してはこのような状況でも 0かそうでないかで影響はありました。 ↩
ちなみに後の方に書いてあります、スクリプト内で
screen
だけを使って新しい ウィンドウを作ると少し変な動作をします。 中で、screen -X screen
とすると、screen
の中での新規ウィンドウを作る、 こまんどなscreen
になるのでそちらを使ったほうが良さそう。 ただ、ここでの話はどちらで書いても全く一緒です。 ↩usleep
コマンド(micro秒sleep)があればusleep 1
でも大丈夫でした ↩