はじめに
Cygwinで作業をすることが多いのですが script
コマンドを使えば、標準出力である画面のログをテキスト形式で残せます。
本記事ではその作業ログの取得を逐次実施せずに自動で行えるようにした際のメモです。
scriptコマンドの説明
scriptコマンドの使い方は、ターミナルで script と打てば利用できます。。
標準出力は以下のようになります。
$ script スクリプトを開始しました。ファイルは typescript です
ここから記録が ./typescript に始まり、終了する際は exit と打てば終了します。
$ exit exit スクリプトを終了しました。ファイルは typescript です
オプションや引数をつけることで、ファイルを上書きしたりファイル名を指定もできます。
自動化する際のポイント
問題はこれを起動時に自動で実行しようとする際です。
単純に .bashrc に 以下のように加筆すると
script
と書くと失敗します。
以下が私の環境で実際に上記の記述を.bashrcに行い、起動した際の出力です。
スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です スクリプトを開始しました。ファイルは typescript です
実はscriptコマンドは新たにシェルを立ち上げる挙動します。
新たなシェルが立ち上がる→scriptコマンド実行→新たなシェルが... の無限ループになるみたいですね。
scriptコマンド実行前後のプロセスを見てみます。
$ ps PID PPID TTY STIME COMMAND 13052 1 ? 01:08:49 /usr/bin/mintty 6288 1936 pty0 01:08:56 /usr/bin/ps 1936 13052 pty0 01:08:49 /usr/bin/bash $ script スクリプトを開始しました。ファイルは typescript です $ ps PID PPID TTY STIME COMMAND 1288 5712 pty0 01:09:01 /usr/bin/script 11180 4176 pty1 01:09:04 /usr/bin/ps 5712 1936 pty0 01:09:01 /usr/bin/script 4176 1288 pty1 01:09:02 /usr/bin/bash 13052 1 ? 01:08:49 /usr/bin/mintty 1936 13052 pty0 01:08:49 /usr/bin/bash
scriptコマンドに伴い、pty1が立ち上がってカレントシェルが変更になっています。
対策方針
今回は簡易的に、現在のシェルの親プロセスが /usr/bin/mintty な場合にのみ script を動かすようにします。
autoscript.shというスクリプトを記述しました。実行できるように適切な権限を付与ください。
※シェルスクリプトの権限の違いについて実証した別記事
www.mtioutput.com
実装
直接.bashrcに記述してもいいですが、テストしやすかったのでそのままshファイルを起動するという構成にしています。
#!/bin/sh ppcheck=`ps | grep $PPID | grep -v pty | awk '{print $8}'` ttynum=`echo \`tty\` | awk '{print substr($0,(length($0)+1)-1,1)}'` nowtime=`date +"%Y%m%d%H%M%S"` filename="${nowtime}_${ttynum}" if [[ ${ppcheck} = "/usr/bin/mintty" ]]; then script -f script_log/$filename fi
ppcheckという変数に現在のシェルの親プロセスのIDを取り込み、そこで現在のttyの最後の数字と現在の時刻とするファイル名でログをとる、という流れですね。
こうしておけばscriptで立ち上がったシェルの親プロセスは/usr/bin/minttyではなくなるので、ループは起きないといった流れです。
ファイル名は、時刻だけだと同時にCygwinの窓を複数立ち上げると被ってしまう可能性があると思い、一意にするべくttyから値を持ってきてます。
これを起動時に実行するために .bashrc に以下のように記載します。
. ./autoscript.sh
明示的にカレントシェルで実行するよう記述しているのは、親プロセスが変わってしまうのを防ぐためです。
以下を記載した上でCygwinを立ち上げると
スクリプトを開始しました。ファイルは script_log/20170129011831_0 です
$ ls script_log/
20170129011831_0
と、しっかり機能しています。
とりあえずこれで運用してみて、挙動が怪しい場合にはまたその都度修正していこうと思います。
Cygwinをお使いの方で、同じようなことに興味がある方はご参考ください。