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타이밍의 일부입니다.

time한 가지 해결책은 외부 명령을 사용하는 것입니다 . 외부 명령에서 작동하므로 쉘 확장은 타이밍의 일부가 아닙니다. 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파이프라인의 각 섹션에 대해 하나씩 두 줄이 제공됩니다.

관련 정보