2018年5月29日火曜日

tmux-agent にプロンプト待ちと進捗メッセージ出力の機能追加

tmux-agent (過去ブログ)に2つの機能を追加しました。

プロンプト待ち機能

  • pane-command に wait_prompt を指定すると、次の行の pane-command に指定されたコマンド実行を、プロンプトによく用いられる文字である #,$,>,:,% がターミナルの末尾に表示されるまで待つようになります。
  • 下記のように ssh でリモートホストにログインしてからコマンド実行したいと思う場合、ログインに数秒単位で時間を要してしまうと、 tmux の send-keys によって渡される文字列がコマンド受付可能になる前に渡されてしまい、コマンドとして処理できない場合があります。

    session:
      pane-command: ssh ${argv}.remote.remote.remote.example.com
      pane-command: tail -f /var/log/nginx/access.log
      pane: web{01..10}
    
  • wait_prompt を利用すると、プロンプトが表示されてから以降のコマンドが実行されます。

    session:
      pane-command: ssh ${argv}.remote.remote.remote.example.com
      pane-command: wait_prompt
      pane-command: tail -f /var/log/nginx/access.log
      pane: web{01..10}
    
  • wait_prompt を利用すると最低でも一箇所で 0.3 秒は待ちが発生するため、むやみに使うと tmux-agent によるセットアップに時間を要するようになります。リモートログイン後のコマンド実行に支障がある状況でのみ利用するのがオススメです。

進捗メッセージ出力機能

  • window や pane のセットアップ時に、標準エラー出力に進捗メッセージを表示するようにしました。
  • 多数のホストへの接続やコマンドの実行、また上記のプロンプト待ち機能を利用するとセットアップ完了まで数十秒単位で時間がかかる事もあるわけですが、進捗メッセージが出るだけで「今どうなってる?」のストレスを緩和したくて追加した機能です。

今回の改修に利用した tmux の機能について

ここからは、主に自分向けの「ここどうやって実現したっけ?」という備忘録です。

進捗メッセージ出力は単に数カ所で echo で出力しただけで tmux の機能は特に利用してません。

プロンプト待ち機能には capture-pane の機能を使いました。この機能は、 pane のバッファの内容を表示したりファイルに出力できたりします。

今回の改修では、tmux capture-pane -p で得たセットアップ中の pane のバッファの内容から、最終行 (空白行は除去) の末尾の文字 (zsh の右プロンプトとかは [ ] で括られていれば除去) を下記のようなワンライナーで抽出し、この文字列がプロンプトで用いられているものか否か、で次のコマンドの実行可否を判定させてます。

$ tmux capture-pane -p \
    | grep -v ^$ | tail -1 \
    | sed 's/[ ]\+[^ ]\+\]$//' \
    | sed 's/[ ]\+$//' \
    | rev | cut -c 1

ただ、ターミナルに文字列が流れてる際にたまたまヒットする可能性もあるため、一定時間同じ文字列のままであることも次のコマンド実行の条件に含めています。あまり長時間判定させてもセットアップに時間がかかるので、今のところ 0.1秒ごとに文字を抽出し、0.1, 0.2 秒前の文字も一致する場合に次のコマンドを実行するようにしてます。ここは今後、実際に使ってみてチューニングが必要になるかもしれないと思ってます。

tmux 自体は send-keys でターミナルに送りつけた文字列がコマンドとして実行されたとしても、そのコマンドの応答自体を直接受け取れない(たぶん)ので、プロンプトを待つようなことは難しいかなぁと思ってましたが、やりようはあるんだなぁといった感じでした。もしかするともっとエレガントなやり方もあるのかもしれませんが。

おまけ: pane-layout に関するドキュメントの改修

久々に pane-layout の機能を使おうとして、自分が書いたドキュメント見てもパッとわからず、少しハマってしまいました。最後の pane キーの直上に書くのに気づくのにしばしかかりました。

具体的には、こんなふうに書いてみたりしちゃって動かないなと。

session:
  pane-layout: c2fa,81x19,0,0[81x9,0,0{38x9,0,0,0,42x9,39,0,3},81x9,0,10,1]
  pane-command: ssh web
  pane: web
  pane-command: ssh ap
  pane: ap
  pane-command: ssh db
  pane: db

ああ、こうするんだった、と。

session:
  pane-command: ssh web
  pane: web
  pane-command: ssh ap
  pane: ap
  pane-command: ssh db
  pane-layout: c2fa,81x19,0,0[81x9,0,0{38x9,0,0,0,42x9,39,0,3},81x9,0,10,1]
  pane: db

自分でこうなので、他の人からはそりゃ分からんよなぁって事でそこらへんを多少分かりやすく書き換えました。

2017年10月28日土曜日

写真も動画も撮影日付 (EXIF ヘッダ内情報) でフォルダ分けする Ruby スクリプト

表題のツール image-relocate のご紹介です。

しばらく前に作った photo-relocate (過去記事) について動画もサポートするようにしたものです。

やりたいことそのものは過去記事のとおりですが、そちらのスクリプトは Ruby の exifr ライブラリ依存のため、JPEG 画像しか取り扱えず、同様な EXIF 情報を有する MP4 や AVCHD 形式のファイルについて日付でフォルダ分けができず不便に思っていました。

今回のスクリプトは Ruby で作ってはいますが、 exiftool スクリプトをシェル経由で呼び出すようにしており、動画形式も同様に日付でフォルダ分け可能になりました。

ファイルごとに都度スクリプトを呼び出す分、photo-relocate より少々遅いのが欠点です。

MacOS, Linux 環境での写真・動画のフォルダ分けのお役に立てば幸いです。