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)

对于我的情况,这种方法几乎作品。然而,这种方法被认为是不好的,因为它违反了一些规则Bash常见问题解答。例如,“不要将代码放入变量中”来自Bash 常见问题解答#50(也可以看看Bash常见问题解答 #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)

相关内容