Bash: 경과 시간을 측정하기 위해 명령을 래핑하는 방법은 무엇입니까?

Bash: 경과 시간을 측정하기 위해 명령을 래핑하는 방법은 무엇입니까?

경과 시간을 측정하기 위해 명령을 어떻게 래핑할 수 있나요?

현재 나는 다음을 사용합니다 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

  1. 명령(및 인수)을 캡처하여대량으로그럼 피할 수 있어eval
  2. 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)

관련 정보