경과 시간을 측정하기 위해 명령을 어떻게 래핑할 수 있나요?
현재 나는 다음을 사용합니다 eval
:
do_cmd_named()
{
local name=$1
local cmd=$2
echo "$name"
local start_time=$(date +%s)
eval "$cmd 2>&1"
local exit_status=$?
local end_time=$(date +%s)
local elapsed_time_sec=$((end_time-start_time))
local elapsed_time_min_sec=$(date -ud "@$elapsed_time_sec" +'%M:%S')
if [[ $exit_status -ne 0 ]]
then
echo "$name failed with exit status $exit_status (elapsed time $elapsed_time_min_sec)"
return $exit_status
else
echo "$name done (elapsed time $elapsed_time_min_sec)"
fi
}
job()
{
sleep 1
}
do_cmd_named "do job" "job"
그 결과는 다음과 같습니다.
do job
do job done (elapsed time 00:01)
내 경우에는 이 접근 방식거의일하다. 그러나 이 방법은 일부 규칙을 위반하기 때문에 나쁜 것으로 간주됩니다.배쉬 FAQ. 예를 들어 "변수에 코드를 넣지 마십시오"는 다음에서 유래합니다.배쉬 FAQ #50(당신은 또한 볼 수 있습니다배쉬 FAQ #48).
그래서 질문은: 이것을 올바르게 수행하는 방법은 무엇입니까?
답변1
- 명령(및 인수)을 캡처하여대량으로그럼 피할 수 있어
eval
- Bash 내장 변수 사용
$SECONDS
do_cmd_named() {
local name=$1
shift
local -a cmd=("$@")
echo "$name"
SECONDS=0
"${cmd[@]}"
local status=$?
local elapsed_time_sec=$SECONDS
# print messages ...
}
do_cmd_named "job name" job arg1 arg2
$SECONDS의 문제점은 중첩된 호출의 경우 $SECONDS가 0으로 재설정된다는 것입니다.
그래 이건 사실이야.
또 다른 접근 방식은 함수 시작 부분에서 SECONDS의 현재 값을 캡처하고 끝 부분에서 일부 산술을 수행하는 것입니다.
한 가지 예:
rectest() {
local n=$1 delay=$2 start=$SECONDS
((n == 3)) && return
sleep $delay
rectest $((n + 1)) $((delay + 3))
echo "at level $n, delay is $delay and duration is $((SECONDS - start))"
}
실행하면 15초 후에 모든 출력이 표시됩니다.
$ rectest 0 2
at level 2, delay is 8 and duration is 8
at level 1, delay is 5 and duration is 13
at level 0, delay is 2 and duration is 15
답변2
zsh로 전환할 수 있는 옵션이 있는 경우:
$ TIMEFMT='%J done (elapsed time: %E)'
$ time sleep 1
sleep 1 done (elapsed time: 1.00s)