一連の入力変数のプログラム実行時間を測定したいと思います(私はzshを使用しています)。
for i in {1..3} ; do time sleep $i ; done
出力は次のとおりです
sleep $i 0,00s user 0,00s system 0% cpu 1,003 total
sleep $i 0,00s user 0,00s system 0% cpu 2,003 total
sleep $i 0,00s user 0,00s system 0% cpu 3,002 total
でもそうだったらいいな
sleep 1 0,00s user 0,00s system 0% cpu 1,003 total
sleep 2 0,00s user 0,00s system 0% cpu 2,003 total
sleep 3 0,00s user 0,00s system 0% cpu 3,002 total
time
すべての変数をその値に置き換えて実際のコマンドを印刷するにはどうすればよいですか?
サブシェルでプログラムを実行してみましたが、期待どおりに出力は変わりません。
for i in {1..3} ; do time (sleep $i) ; done
i
私のプログラムはstdoutとstderrの独自の出力を生成するので、次のように、単にすべての引数(それらだけでなく)の前に追加する方法が見つかりませんでした。
for i in {1..3} ; do echo -n "i=$i --> " ; time sleep $i ; done
答え1
time
これは、キーワードが複合コマンドに適用される可能性があるために発生します。 (より正確にはパイプで動作します。)次のように書くことができます。
time (i=$(($(/bin/echo 1) + 1)); sleep $i)
zshがコマンド(計算を含む)を解析するのにかかる時間は$i
タイミングの一部です。
time
1つの解決策は外部コマンドを使用することです。外部コマンドで動作するため、シェル拡張はタイミングの一部ではありません。 GNU時間の使用(コマンドはデフォルトでは印刷されません):
% for i in {1..3} ; do =time -f '%C %Us user %Ss system %P cpu %e total' sleep $i ; done
sleep 1 0.00s user 0.00s system 0% cpu 1.00 total
sleep 2 0.00s user 0.00s system 0% cpu 2.00 total
sleep 3 0.00s user 0.00s system 0% cpu 3.00 total
別の解決策は、コマンドを直接印刷することです。以下のコードは、コマンド出力(存在する場合)の前にコマンドテキストを印刷します。
% for i in {1..3} ; do echo -n "sleep $i"; (TIMEFMT=${TIMEFMT#%J}; time sleep $i); done
sleep 1 0.00s user 0.00s system 0% cpu 1.004 total
sleep 2 0.00s user 0.00s system 0% cpu 2.004 total
sleep 3 0.00s user 0.00s system 0% cpu 3.004 total
別の回避策は、コマンドトレースを有効にすることです。
% for i in {1..3} ; do (TIMEFMT=${TIMEFMT#%J}; set -x; time sleep $i); done
+zsh:14> sleep 1
0.00s user 0.00s system 0% cpu 1.004 total
+zsh:14> sleep 2
0.00s user 0.00s system 0% cpu 2.004 total
+zsh:14> sleep 3
0.00s user 0.00s system 0% cpu 3.005 total
別の解決策は、必要なテキストを時間形式に挿入することです。
% for i in {1..3} ; do (TIMEFMT="${${:-sleep $i}//\%/%%}${TIMEFMT#%J}"; time sleep $i); done
sleep 1 0.00s user 0.00s system 0% cpu 1.004 total
sleep 2 0.00s user 0.00s system 0% cpu 2.004 total
sleep 3 0.00s user 0.00s system 0% cpu 3.004 total
別の解決策は、可能な限り単純なシェルコマンドを設定することですeval
。これが関連しているので、eval
コマンドにシェル特殊文字を含めることができることに注意してください。
% for i in {1..3} ; do eval "time sleep $i"; done
sleep 1 0.00s user 0.00s system 0% cpu 1.002 total
sleep 2 0.00s user 0.00s system 0% cpu 2.005 total
sleep 3 0.00s user 0.00s system 0% cpu 3.004 total
答え2
次のことができます。
$ for i in {1..3} ; do eval "time sleep $i:q"; done
sleep 1 0.00s user 0.00s system 0% cpu 1.004 total
sleep 2 0.00s user 0.00s system 0% cpu 2.003 total
sleep 3 0.00s user 0.00s system 0% cpu 3.002 total
(:q
この場合、数字のみが含まれている場合は不要ですが、通常の場合は、$i
どのコマンドにリテラル引数として何かを渡したい場合に必要です。)$i
%J
いつでも好きなテキストに置き換えることができます(タスク名1に展開されます)$TIMEFMT
。
for i in {1..3}; do
TIMEFMT="sleep $i: %U user %S system %P cpu %*E total"
time sleep $i
done
(%
このテキストに含めるにはエスケープする必要があることに注意してください%%
。)
実際、それは役職の実際の名前ではありません。たとえば、time sleep 1 | sleep 2
パイプライン全体がジョブの場合、time
パイプラインの各セクションに1つずつ2行あります。