(O+P)ut

(O+P)ut

(O+P)ut = Out + Put >> OutPut

【Cygwin】作業ログを自動で残す

はじめに

Cygwinでちょこちょこと作業をすることが多いのですが script コマンドを使えば、簡単に作業ログを残せます。

その作業ログの取得を、自動で行えるようにした際のメモです。

scriptコマンドでログ取得

f:id:mtiit:20180813092632j:plain

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というスクリプトを記述しました。実行できるように適切な権限を付与ください。

シェルスクリプトの権限の違いについて実証した別記事
mti.hatenablog.com


実装

*1

#!/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をお使いの方で、同じようなことに興味がある方はご参考ください。

*1:直接.bashrcに記述してもいいですが、テストしやすかったのでそのままshファイルを起動するという構成にしています