zshでのtimeコマンド出力フォーマットをbashっぽくする

2020.01.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

超超小ネタです。

以前、というかこれまでは手元仕事用環境においてはbashを用いていました(MacBook Pro/13inch)。ですがこの度環境を一新しMacOSもCatalinaにアップデート(MacBook Pro/16inch、マシンを買い換える形に)。このOSからは下記エントリなどでも紹介されているように、OSのデフォルトシェルが「bash」から「zsh」に変わっています。

当エントリではそんなシェル環境の変更に際して挙動が変わっていた事象についてのちょっとした対応内容についてまとめておきたいと思います。

zshのtimeコマンド、出力内容のフォーマットがbashのものとは少々異なっている

シェルスクリプトやプログラムを実行する時に『実行時間』を計測するためにtimeコマンドを用いることは良くあることかと思います。

とてもシンプルな以下のスクリプトを用意。3秒間待機するsleepコマンドを挟んで文字列を出力する、とてもシンプルな構成です。

sample.sh

#!/bin/sh
echo "START."
sleep 3
echo "END."

これをbash環境で実行すると以下のような出力結果が得られます。

$ time ./sample.sh
START.
END.
real	0m3.018s
user	0m0.004s
sys	 0m0.003s

ですが、zshで同じスクリプトを実行すると以下のような書式となります。実行時間表示の部分が以下のような形式となっています。内容を読み解くとbashと同じ様なものであると分かるのですが、bashでずっと慣れてきたのもあって内容の出方的にちょっと違和感がありますよね...

% time ./sample.sh
START.
END.
./sample.sh  0.00s user 0.01s system 0% cpu 3.017 total

ということで、この内容をbashっぽく変えたいと思います。

参考にした情報はこちらの内容。

zshでは、TIMEFMTという環境変数を使ってこの部分の表示内容を変更することが出来ます。

2つ目のページ、『15.6 Parameters Used By The Shell』の項に記載されている以下例(※抜粋)が該当する部分となります。

TIMEFMT
The format of process time reports with the time keyword. The default is ‘%J %U user %S system %P cpu %*E total’. 
Recognizes the following escape sequences, although not all may be available on all systems, 
and some that are available may not be useful:

%%
A ‘%’.

%U
CPU seconds spent in user mode.

%S
CPU seconds spent in kernel mode.

%E
Elapsed time in seconds.

%P
The CPU percentage, computed as 100*(%U+%S)/%E.

%W
Number of times the process was swapped.

%X
The average amount in (shared) text space used in kilobytes.

%D
The average amount in (unshared) data/stack space used in kilobytes.

%K
The total space used (%X+%D) in kilobytes.

%M
The maximum memory the process had in use at any time in kilobytes.

%F
The number of major page faults (page needed to be brought from disk).

%R
The number of minor page faults.

%I
The number of input operations.

%O
The number of output operations.

%r
The number of socket messages received.

%s
The number of socket messages sent.

%k
The number of signals received.

%w
Number of voluntary context switches (waits).

%c
Number of involuntary context switches.

%J
The name of this job.

A star may be inserted between the percent sign and flags printing time (e.g., ‘%*E’); 
this causes the time to be printed in ‘hh:mm:ss.ttt’ format (hours and minutes are only printed if they are not zero). 
Alternatively, ‘m’ or ‘u’ may be used (e.g., ‘%mE’) to produce time output in milliseconds or microseconds, respectively.

上記内容を踏まえ、以下の様な設定を.zshrcに追記、反映します。

% vi ~/.zshrc
:
:
TIMEFMT=$'\n\n========================\nProgram : %J\nCPU     : %P\nuser    : %*Us\nsystem  : %*Ss\ntotal   : %*Es\n========================\n'

% source ~/.zshrc

改めてプログラムを実行。以下の様な内容で、bashでの実行時と同じ様な形式(全く同じでは無いですが)で実行時間などの情報を表示させることが出来ました。

% time ./sample.sh
START.
END.


========================
Program : ./sample.sh
CPU     : 0%
user    : 0.002s
system  : 0.004s
total   : 3.009s
========================

まとめ

というわけで、zshにおけるtimeコマンド出力結果のフォーマット調整に関する内容の紹介でした。

bashとzsh、細かいところでちょいちょいコマンドオプションや挙動が異なるので気にはなりつつも、良い感じで違和感無く使えるように色々と試行錯誤しているところです。幾つかトピックがまとまったら、その際には改めてまとめておきたいなと思います。