スクリプトの実行時間を効果的に取得するにはどうすればよいですか?

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

現在行っていることは-

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

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

コメント

回答

Jusスクリプトを呼び出すときは、timeを使用します:

time yourscript.sh 

コメント

  • これは、realusersysの3回出力します。これらの意味については、ここを参照してください。
  • および” real “はおそらく人々が知りたいことです-“実際は実時間です-通話の開始から終了までの時間”
  • stdoutをファイルにキャプチャする方法はありますか?たとえば、time $( ... ) >> out.txt
  • これは、コマンドラインの一連のコマンドに対しても実行できます。例:time (command1 && command2)
  • または、スクリプトで次のようにすることもできます。bashであると仮定して$ SECONDSをエコーします。…

回答

timeがオプションでない場合は、

start=`date +%s` stuff end=`date +%s` runtime=$((end-start)) 

コメント

  • これは、’秒未満の精度が必要ない場合にのみ機能することに注意してください。一部の用途では許容できる場合があります。 、他の人には当てはまりません。精度を少し上げるために(たとえば、’はまだdateを2回呼び出しているので、最良の実際にはミリ秒の精度を取得し、おそらくそれ以下)、date +%s.%Nを使用してみてください(%Nは、秒全体からナノ秒です。)
  • @ChrisHああ、よく指摘します。bashの算術展開は整数のみです。2つのobviが表示されます。 ousオプション;日付形式の文字列でピリオドを破棄する(そして結果の値をエポックからのナノ秒として扱う)ので、date +%s%Nを使用するか、bc jwchewが提案するように、2つの値から実際のランタイムを計算します。それでも、このアプローチはそれを行うには次善の方法だと思います。 timeは、上記の理由により、利用可能な場合はかなり優れています。
  • bcをインストールしてから、次の手順を実行します。runtime=$( echo "$end - $start" | bc -l )
  • スクリプトに数分かかる場合は、次を使用します:echo "Duration: $((($(date +%s)-$start)/60)) minutes
  • さらに@ rubo77コメント、スクリプトに数時間かかる場合は、hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"

回答

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

kshまたはzshの場合、代わりにtimeを使用することもできます。 zshを使用すると、timeは、ユーザーに加えて実時間も提供します。システムのCPU時間。

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

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 

また、bash、とzshには$SECONDS特殊変数があります。この変数は毎秒自動的にインクリメントされます。 zshksh93の両方で、その変数を浮動小数点にすることもできます(typeset -F SECONDS )より正確にするため。これは実時間であり、CPU時間ではありません。

コメント

  • $ SECONDS変数は非常に便利です、ありがとうございます!
  • あなたのアプローチは一時的なイベントの影響を排除しますか? —あなたのアプローチは前に示したtimeアプローチに近いと思います。—ここでは、MATLABコードで示されているtimeitアプローチが役立つと思います。
  • こんにちは、@ St éファンシャゼラス。 timesが’壁時計を与えていないことがわかりましたよね?たとえば、bash -c 'trap times EXIT;sleep 2'
  • @Binarus、はい、その機能はkshからのものです。 ksh93 / zshとは異なり、bashが浮動小数点をサポートしていないことに加えて、’も壊れており、SECONDSを0に設定すると、0から1秒後に1に変更されます( time()の結果のみを考慮します。これは完全な秒の粒度しかありません。
  • @Binarus、それではありません’ sは0から1の間です。12:00:00.000にSECONDSを0に設定すると、1秒後に1に変更されます。ただし、12:00:00.999に設定すると、1ミリ秒後に1に変更されます。しかし、はい、とにかく’ 1秒未満の精度がなければ、’実際にはそれほど重要ではないことに同意します。

回答

私は時流に少し遅れましたが、解決策を投稿したかった(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) LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds 

誰かを希望します

コメント

  • ‘ bc ‘計算を実行します。ところで、非常に優れたスクリプトです;)
  • FreeBSD ‘ ■dateは秒未満の精度をサポートしておらず、タイムスタンプにリテラル「N」を追加するだけです。
  • とても素敵なスクリプトですが、私のbashは’ tはサブセカンド部分を処理します。また、bcの/ 1はそれを効果的に取り除くことを学びました。そのため、$ dsの計算に@ / 1 @を追加すると、非常に優れたものが表示されるようになりました。
  • bcはモジュロをサポートします:dt2=$(echo "$dt%86400" | bc)。ただ言ってください…ところで、私はdt2=$(bc <<< "${dt}%86400")の形式が好きですが、それは’完全に個人的なものです。
  • 私は
  • div id = “1729928497”>

bcについてはまだ何も知りませんが、86400で分割すると、次の理由:86400秒のない日があります。たとえば、時刻がDSTから通常の時刻に、またはその逆に切り替わる日や、うるう秒のある日などです。そのような日が計算したい期間の一部である場合、つまりres1res2(これらの値を含む)の間にある場合、スクリプトおそらく失敗します。

回答

bashのメソッド:

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

コメント

  • これは経過時間を表示しますが、質問で要求されたように、”プロセッサ時間、I / O時間”などのきめ細かい出力を表示しません。
  • 提起された質問に対する回答を検索する人は、この解決策が役立つと思われます。あなたのコメントは、OPの質問に向けたほうがよいでしょう。

回答

個人的には、すべてをまとめたいと思います。次のような「メイン」関数のスクリプトコード:

main () { echo running ... } # stuff ... # calling the function at the very end of the script time main 

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

コメント

  • 優れたソリューション、 ‘追加のツールは必要なく、自己完結型です。

回答

#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime" 

はい、これはPythonを呼び出しますが、それを使用できるのであれば、これは非常に優れた簡潔なソリューションです。

コメント

  • サブシェルでそのpythonコマンドを実行し、その出力を読み取るには、現在のほとんどのシステムで数百万ナノ秒かかることに注意してください。date
  • “数百万ナノ秒”は数ミリ秒です。bashスクリプトのタイミングを計る人々は、通常、それについてあまり心配していません(1メガ秒あたり数十億のスクリプトを実行しない限り)。
  • 計算はPythonプロセス内で行われ、値はPythonが呼び出される前に完全に収集されました。スクリプトの実行時間は、”数百万ナノ秒”のオーバーヘッドなしで正しく測定されます。

ははるかにクリーンです…はい、私たちは多くの劣化を抱えて生きることができますが、’がなくてもはるかに優れているので、’をエンジニアのままにしてください!

  • $(echo $end - $start | bc)はpythonなしでも同じことを行います
  • 回答

    この質問はかなり古いですが、私の好きな方法を見つけようとすると、このスレッドが高くなりました…そして、誰もそれについて言及していないことに驚いています:

    perf stat -r 10 -B sleep 1 

    “perf”は、カーネルの “tools / perf”に含まれているパフォーマンス分析ツールであり、多くの場合、個別のパッケージ(CentOSの “perf”およびDebian / Ubuntuの “linux-tools”)としてインストールできます。 Linux Kernal perf Wiki には、それに関する詳細情報があります。

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

    1.002248382 seconds time elapsed ( +- 0.01% ) 

    コメント

    • perf
    • @Bレイヤー-私の答えを編集しましたt o ‘ perf ‘の簡単な説明を入力します。
    • perf stat “統計を収集する権限がない可能性があります。” 。これにより、ターゲットマシンを完全に所有していない’すべてのシナリオで使用できなくなります。
    • すばらしい、ありがとうございます。他の人が提案しているtimeよりもはるかにきめ細かいソリューション。特に、timeは、コード競合ソリューションの測定には適用されません(’ミリ秒以下の印刷時間ではないため) 、ソリューションはそうです。

    回答

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

    tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code } 

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

    tm the_original_command with all its parameters 

    コメント

    • ミリ秒を追加する価値があります、ilke s=$(date +%s000)を試しましたが、よくわかりません動作する場合。
    • @loretoparisiミリ秒の場合は、date +%s%Nを試してみてください。 serverfault.com/questions/151109/ …
    • を参照してください。

    • これは、安全性を除けばすばらしいことです。 "$@"

    回答

    #!/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 [email protected] #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..." 

    コメント

    • これは、前後にdateを使用する他の回答とどのように異なりますか。スクリプトとそれらの違いを出力しますか?

    回答

    1. ただ time [any command] を使用します。例:time sleep 1は、次のように、約1.000〜約1.020秒のリアルタイム(つまり、ストップウォッチのタイミングで)スリープします:

        $ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s  

      なんて美しいことでしょう。その後に任意のコマンドを置くことができ、人間が読める形式で結果を出力します。タイミングビルドに使用するのが本当に好きです。例:

        # time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target  

      …または実際に発生する可能性のあるgit操作の場合長いので、現実的な精神的期待を育てることができます:

        # time how long it takes to pull from a massive repo when # I"m working from home during COVID-19. NB: `git pull` # is sooooo much slower than just pulling the one branch # you need with `git pull origin <branch>`, so just fetch # or pull what you need! time git pull origin master  
    2. よりカスタマイズされたタイミングのニーズでは、bashで出力を操作したり他の形式に変換したりする必要があります、内部の$SECONDS変数を使用します。 ここに、これらの秒を浮動小数点分などの他の単位に変換するデモが含まれています:

      dt_min0.01666666666...(1秒=その分)から0.017に丸められることに注意してください。この場合、printf関数を使用して丸めているためです。以下のsleep 1;の部分では、スクリプトを呼び出して実行と時間を計りますが、このデモのために、代わりに1秒間だけスリープしています。

      コマンド:

        start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \ dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \ echo "dt_sec = $dt_sec; dt_min = $dt_min"  

      出力:

        dt_sec = 1; dt_min = 0.017  

    関連:

    1. 続きを読むここでの私の答えのbcprintfについて: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
    2. timeコマンドについて最初にどこで学んだかはもう覚えていませんが、

      @Trudbertの回答はここにあります。

    回答

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

    start=$SECONDS ... # do time consuming stuff end=$SECONDS 

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

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

    増分期間のみが必要な場合は、次のようにします。

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

    期間を変数に格納することもできます:

    let diff=end-start 

    コメント

    回答

    は、第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 

    回答

    組み込みのbash時間を使用しますか?

    time: time [-p] PIPELINE Execute PIPELINE and print a summary of the real time, user CPU time, and system CPU time spent executing PIPELINE when it terminates. The return status is the return status of PIPELINE. The `-p" option prints the timing summary in a slightly different format. This uses the value of the TIMEFORMAT variable as the output format. 

    例:

    TIMEFORMAT="The command took %Rs" time { sleep 0.1 } 

    出力:

    The command took 0.108s 

    回答

    ここにAlexのバリエーションがあります「答え。分と秒だけが気になりますが、フォーマットを変えたいと思ったので、こうしました:

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

    コメント

    • なぜ反対票を投じるのですか?バグはありますか?
    • その計算にpythonを使用することは、私にとってもバグのように見えます。ごめんなさい。人々が’に電話をかけることができない理由timeは私を超えています。

    回答

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

    回答

    受け入れられたソリューションtimeを使用するとstderrに書き込みます。
    timesを使用するソリューションはtimes
    $SECONDSを使用するソリューションには、1秒未満の精度がありません。
    他のソリューションには、次のような外部プログラムの呼び出しが含まれます。 dateまたはperfは効率的ではありません。
    これらのいずれかに問題がない場合は、それを使用してください。

    ただし、時間を取得するために効率的なソリューションが必要な場合ミリ秒の精度で、変数に必要です 元の出力は影響を受けませんプロセス置換とtime周辺のリダイレクトを組み合わせることができます。これは呼び出すよりもはるかに高速です外部プログラムであり、元のコマンド/スクリプトと同様にタイミングラッパースクリプトをリダイレクトできます。

    # Preparations: Cmd=vgs # example of a program to be timed which is writing to stdout and stderr Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }" # other example; replace with your own TIMEFORMAT="%3R %3U %3S" # make time output easy to parse 


    $Cmdstdout$Cmdに書き込まれる最短のバリアントdiv id = “555ddc9905”> およびstdoutには何もありません:

    read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3) 

    保持するより長いバリアント元のstdoutstderrは互いに分離しています:

    { read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1 

    最も複雑なバリアントには、$Cmdがこのタイミングラッパーなしで呼び出されるように追加のファイル記述子を閉じることが含まれます。ivid = vgsのような “5fa1270707”> コマンドは、リークされたファイル記述子について文句を言いません:

    { read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1 

    あなたbcを呼び出さなくても、bashで浮動小数点の追加を偽造することもできますが、これははるかに遅くなります:

    CPU=`printf %04d $((10#${User/.}+10#${System/.}))` # replace with your own postprocessing echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2 # redirected independent of $Cmd 

    低速CPUでの$Cmdの2つの例で可能な出力:

    File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash VG #PV #LV #SN Attr VSize VFree b3 3 24 0 wz--n- 1.31t 1.19t CPU 0.052 s, Elapsed 0.056 s 

    または:

    stdout stderr CPU 0.008 s, Elapsed 0.109 s 

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です