経過時間を測定するためにコマンドをどのようにラップできますか?
現在私は以下を使用していますeval
:
do_cmd_named()
{
local name=$1
local cmd=$2
echo "$name"
local start_time=$(date +%s)
eval "$cmd 2>&1"
local exit_status=$?
local end_time=$(date +%s)
local elapsed_time_sec=$((end_time-start_time))
local elapsed_time_min_sec=$(date -ud "@$elapsed_time_sec" +'%M:%S')
if [[ $exit_status -ne 0 ]]
then
echo "$name failed with exit status $exit_status (elapsed time $elapsed_time_min_sec)"
return $exit_status
else
echo "$name done (elapsed time $elapsed_time_min_sec)"
fi
}
job()
{
sleep 1
}
do_cmd_named "do job" "job"
その結果は次のとおりです。
do job
do job done (elapsed time 00:01)
私の場合、このアプローチほぼ働くただし、この方法はいくつかの規則に違反しているため、悪いと見なされます。バッシュFAQ。たとえば、「変数にコードを入れないでください」は、以下に由来します。バッシュFAQ #50(あなたも見ることができますバッシュFAQ #48)。
だから質問は:これを正しく行う方法は?
答え1
- コマンド(および引数)をキャプチャして大量にそれから避けることができます
eval
- Bash 組み込み変数の使用
$SECONDS
do_cmd_named() {
local name=$1
shift
local -a cmd=("$@")
echo "$name"
SECONDS=0
"${cmd[@]}"
local status=$?
local elapsed_time_sec=$SECONDS
# print messages ...
}
do_cmd_named "job name" job arg1 arg2
$ SECONDSの問題は、ネストされた呼び出しの場合は$ SECONDSが0にリセットされることです。
ええ、これは本当です。
別のアプローチは、関数の先頭でSECONDSの現在の値を取得し、最後でいくつかの算術を実行することです。
一例:
rectest() {
local n=$1 delay=$2 start=$SECONDS
((n == 3)) && return
sleep $delay
rectest $((n + 1)) $((delay + 3))
echo "at level $n, delay is $delay and duration is $((SECONDS - start))"
}
実行すると、15秒後にすべての出力が表示されます。
$ rectest 0 2
at level 2, delay is 8 and duration is 8
at level 1, delay is 5 and duration is 13
at level 0, delay is 2 and duration is 15
答え2
zshに切り替えるオプションがある場合:
$ TIMEFMT='%J done (elapsed time: %E)'
$ time sleep 1
sleep 1 done (elapsed time: 1.00s)