スクリプトの実行時間を効果的に取得する方法は?


340

スクリプトの完了時間を表示したいと思います。

私が現在していることは-

#!/bin/bash
date  ## echo the date at start
# the script contents
date  ## echo the date at end

これは、スクリプトの開始時と終了時を示しています。プロセッサー時間/入出力時間などのようなきめ細かい出力を表示することは可能でしょうか?



現在受け入れられている答えは、時間的な変動のために実際には十分ではないと思います。
レオレオポルトヘルツ준영

1
@CiroSantilli烏坎事件2016六四事件法轮功あなたの提案したスレッドは、一時的なイベントの影響を排除するにはまだ十分ではないと思います。
レオレオポルドヘルツ


あなたが実行できるコマンドがあり、それからすべてのunixコマンドを自動的に時間計測します。
powder366

回答:


449

timeスクリプトを呼び出すときに使用します。

time yourscript.sh

61
これは3回出力されます:realuserおよびsys。これらの意味については、こちらを参照してください
ギャレット

27
「本物」はおそらく人々が知りたいことです-「本物は壁時計時間です-通話の開始から終了までの時間」
ブラッドパークス

3
標準出力をファイルにキャプチャする方法はありますか?例えば、のようなものtime $( ... ) >> out.txt
ジョン

1
コマンドラインでコマンドのシーケンスにこれを行うこともできます。たとえば、次のtime (command1 && command2)
とおりです。– meetar

1
それとも彼は、彼のスクリプトで、単に行うことができます:$ SECONDSエコー....それはbashのであると仮定すると
Crossfit_and_Beer

170

場合はtimeオプションではありません、

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))

30
これは、1秒未満の精度が必要ない場合にのみ機能することに注意してください。受け入れられるかもしれないいくつかの用途では、他の用途ではそうではありません。わずかに精度を上げるには(dateたとえば、まだ2回呼び出しているので、実際にはせいぜいミリ秒の精度しか得られない可能性があります)、を使用してみてくださいdate +%s.%N。(%N全体の秒からナノ秒です。)
CVn

いい視点ね。私はキーボードを離れた直後にそのことを考えましたが、戻ってきませんでした。^^また、OP、「日付」自体がランタイムに数ミリ秒を追加することを忘れないでください。
ロブ・ボス

2
@ChrisHああ。それを指摘するのは良いことです。bash算術展開は整数のみです。2つの明白なオプションがあります。日付書式文字列で期間を捨て(およびエポックからのナノ秒のように結果の値を扱う)、そう使用するかdate +%s%N、など多くの可能なものを使用bcjwchewが示唆のような二つの値から実際のランタイムを計算します。それでも、このアプローチは最適な方法ではないと感じています。time上記の理由により、利用可能な場合はかなり優れています。
CVn 14年

10
ただインストールbcしてから、この操作を行います。runtime=$( echo "$end - $start" | bc -l )
しのばせる

10
スクリプトに数分かかる場合は、次を使用しますecho "Duration: $((($(date +%s)-$start)/60)) minutes
。– rubo77

75

timesスクリプトを終了するときに引数なしで呼び出すだけです。

ではkshまたはzsh、あなたも使用することができますtime代わりに。ではzshユーザーシステムの CPU時間timeに加えて、ウォールクロック時間も提供されます。

スクリプトの終了ステータスを保持するには、次のようにします。

ret=$?; times; exit "$ret"

または、次の場所にトラップを追加することもできますEXIT

trap times EXIT

これにより、シェルが終了するたびに時間が呼び出され、終了ステータスが保持されます。

$ bash -c 'trap times EXIT; : {1..1000000}'
0m0.932s 0m0.028s
0m0.000s 0m0.000s
$ zsh -c 'trap time EXIT; : {1..1000000}'
shell  0.67s user 0.01s system 100% cpu 0.677 total
children  0.00s user 0.00s system 0% cpu 0.677 total

また、すべてのことに注意してくださいbashkshzsh持って$SECONDS自動的秒ごとにインクリメントます特殊変数を。zshおよびの両方でksh93、その変数を浮動小数点(withでtypeset -F SECONDS)にして、精度を高めることもできます。これは実時間であり、CPU時間ではありません。


12
その$ SECONDS変数は非常に便利です、ありがとう!
andybuckley

あなたのアプローチは、一時的なイベントの影響を排除しますか?--あなたのアプローチはtime前に示したアプローチに近いと思います。-- timeitここでは、MATLABコードで示されているアプローチが役立つと思います。
レオレオポルトヘルツ

2
こんにちは、@StéphaneChazelas。私timesは壁の時間を与えないことがわかりましたよね?たとえば、bash -c 'trap times EXIT;sleep 2'
user15964


32

私は時流に少し遅れていますが、他の人が検索を通じてこのスレッドにつまずく場合に備えて、(1秒未満の精度で)私のソリューションを投稿したかったです。出力は、日、時間、分、最後に秒の形式です。

res1=$(date +%s.%N)

# do stuff in here

res2=$(date +%s.%N)
dt=$(echo "$res2 - $res1" | bc)
dd=$(echo "$dt/86400" | bc)
dt2=$(echo "$dt-86400*$dd" | bc)
dh=$(echo "$dt2/3600" | bc)
dt3=$(echo "$dt2-3600*$dh" | bc)
dm=$(echo "$dt3/60" | bc)
ds=$(echo "$dt3-60*$dm" | bc)

printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

誰かがこれが役に立つことを願っています!


1
計算を行うために 'bc'を使用する以外に、他の(bashのみ)方法はないと思います。ところで本当に良いスクリプト;)
tvl

1
FreeBSD dateは1秒未満の精度をサポートせずN、タイムスタンプにリテラル「」を追加するだけであることに注意してください。
アントンサムソノフ

1
非常に素晴らしいスクリプトですが、私のbashは1秒未満の部分を処理しません。また、bcの/ 1がそれを効果的に除去することもわかったので、$ ds計算に@ / 1 @を追加しました。
ダニエル

1
bcはmodulo:をサポートしますdt2=$(echo "$dt%86400" | bc)。ただ言って...ところで私はフォームdt2=$(bc <<< "${dt}%86400")が好きですが、それは完全に個人的なものです。
-Dani_l

16

私の方法bash

# Reset BASH time counter
SECONDS=0
    # 
    # do stuff
    # 
ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"

これは経過時間を表示しますが、質問で要求されている「プロセッサ時間、I / O時間のようなきめ細かい出力」は表示しません。
ロアイマ

3
提起された質問に対する答えを探している人は、この解決策が役立つと思うでしょう。あなたのコメントは、OPsの質問により適切に対処されるでしょう。
マーク

5
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

はい、これはPythonを呼び出しますが、それと一緒に暮らすことができれば、これは非常に優れた簡潔なソリューションです。


5
そのpythonコマンドをサブシェルで実行し、その出力を読み取るには、ほとんどの現在のシステムで数百万ナノ秒かかることに注意してください。実行中も同じですdate
ステファンシャゼル14年

7
「数百万ナノ秒」は数ミリ秒です。通常、bashスクリプトのタイミングを計る人は、それについてあまり気にしません(メガ秒あたり数十億のスクリプトを実行しない限り)。
ジルク

2
また、計算がpythonプロセス内で行われた場合でも、pythonが呼び出される前に値が完全に収集されたことに注意してください。「数百万ナノ秒」のオーバーヘッドなしで、スクリプトの実行時間は正しく測定されます。
ビクターシュレーダー

5

この質問はかなり古いですが、私のお気に入りのやり方を見つけようとすると、このスレッドが高くなりました...

perf stat -r 10 -B sleep 1

「perf」は「tools / perf」の下のカーネルに含まれるパフォーマンス分析ツールであり、多くの場合、個別のパッケージとしてインストールできます(CentOSの「perf」とDebian / Ubuntuの「linux-tools」)。 Linux Kernal perf Wikiには、さらに多くの情報があります。

「perf stat」を実行すると、最後の平均実行時間など、かなりの詳細が表示されます。

1.002248382 seconds time elapsed                   ( +-  0.01% )

2
なにperf
Bレイヤー

@Bレイヤー-回答を編集して、「perf」の簡単な説明を追加しました。
ザハイド

1
perf stat現在、「統計情報を収集する権限がない可能性があります」と文句を言います。でコマンドを実行しない限りsudo、ターゲットマシンを完全に所有していないすべてのシナリオで役に立たなくなります。
アラマー

4

コマンドの前に追加して時間を測定できる小さなシェル関数:

tm() {
  s=$(date +%s)
  $@
  rc=$?
  echo "took $[$(date +%s)-$s] seconds. return code $rc" >&2
  return $rc
}

次に、スクリプトまたはコマンドラインで次のように使用します。

tm the_original_command with all its parameters

ミリ秒を追加する価値があり、ilkeを試しましたがs=$(date +%s000)、うまくいくかどうかはわかりません。
ロレトパリシ

3

アレックスの答えのバリエーションを次に示します。数分と数秒しか気にしませんが、フォーマットを変えたいと思いました。だから私はこれをやった:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")

1
なぜ下票なのですか?バグはありますか?
mpontillo 16

3
#!/bin/csh
#PBS -q glean
#PBS -l nodes=1:ppn=1
#PBS -l walltime=10:00:00
#PBS -o a.log
#PBS -e a.err
#PBS -V
#PBS -M shihcheng.guo@gmail.com
#PBS -m abe
#PBS -A k4zhang-group
START=$(date +%s)
for i in {1..1000000}
do
echo 1
done
END=$(date +%s)
DIFF=$(echo "$END - $START" | bc)
echo "It takes DIFF=$DIFF seconds to complete this task..."

7
これはdate、スクリプトの前後に使用し、それらの違いを出力する既に与えられた他の回答とはどう違うのですか?
エリックルヌーフ

2

bash のみを使用すると、シェルスクリプトの一部の期間(またはスクリプト全体の経過時間)を測定および計算することもできます。

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

差を印刷することができます:

echo "duration: $((end-start)) seconds."

増分期間のみが必要な場合:

echo "duration: $((SECONDS-start)) seconds elapsed.."

期間を変数に保存することもできます。

let diff=end-start

^これが回答者です。またはもっと簡単に:最後に$ SECONDS。これは、組み込みのBash変数です。他の答えはすべて、この車輪を再発明するために余分な仕事をしているだけです...
Crossfit_and_Beer

2

個人的には、すべてのスクリプトコードを次のような「メイン」関数にラップするのが好きです。

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

timeこのシナリオでコマンドを使用するのがいかに簡単かを確認してください。明らかに、スクリプトの解析時間を含む正確な時間を測定しているわけではありませんが、ほとんどの状況で十分正確であることがわかります。


1
#!/bin/bash
begin=$(date +"%s")

Script

termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."

1

に基づくタイミング関数はSECONDS、第2レベルの粒度のみに制限され、外部コマンドを使用しません。

time_it() {
  local start=$SECONDS ts ec
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Starting $*"
  "$@"; ec=$?
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Finished $*; elapsed = $((SECONDS-start)) seconds"
  # make sure to return the exit code of the command so that the caller can use it
  return "$ec"
}

例えば:

time_it sleep 5

与える

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished
sleep 5; elapsed = 5 seconds
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.