zsh の time コマンド出力に変数値を表示します。

zsh の time コマンド出力に変数値を表示します。

一連の入力変数のプログラム実行時間を測定したいと思います(私は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タイミングの一部です。

time1つの解決策は外部コマンドを使用することです。外部コマンドで動作するため、シェル拡張はタイミングの一部ではありません。 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行あります。

関連情報