【问题标题】:Storing execution time of a command in a variable将命令的执行时间存储在变量中
【发布时间】:2014-10-19 17:54:29
【问题描述】:

我正在尝试为命令行编写任务运行程序。没有道理。只是想这样做。基本上它只是运行一个命令,将输出存储在一个文件中(而不是标准输出),同时在标准输出上打印一个进度指示器,当它全部完成后,打印Completed ($TIME_HERE)

代码如下:

#!/bin/bash
task() {
  TIMEFORMAT="%E"
  COMMAND=$1
  printf "\033[0;33m${2:-$COMMAND}\033[0m\n"
  while true
  do
    for i in 1 2 3 4 5
    do
      printf '.'
      sleep 0.5
    done
    printf "\b\b\b\b\b     \b\b\b\b\b"
    sleep 0.5
  done &
  WHILE=$!
  EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1)
  kill -9 $WHILE
  echo $EXECTIME
  #printf "\rCompleted (${EXECTIME}s)\n"
}

我承认里面有一些不必要的花哨的东西。但是我经历了大量的 StackOverflow 问题来做不同类型的花哨的东西只是来尝试一下。如果将其应用于任何地方,可以减少大量脂肪。但事实并非如此。

应该这样称呼:

task "ping google.com -c 4" "Pinging google.com 4 times"

它会用黄色打印Pinging google.com 4 times,然后在下一行打印一个句点。然后每隔 0.5 秒打印一个周期。五个周期后,从同一行的开头开始并重复此操作,直到命令完成。然后它应该打印Complete ($TIME_HERE)(显然)代替$TIME_HERE执行命令所花费的时间。 (我已经把那部分注释掉了,当前版本只会打印时间)。

问题

问题在于,打印出来的不是执行时间,而是一些非常奇怪的东西。这可能是我正在做的愚蠢的事情。但我不知道这个问题是从哪里来的。这是输出。

$ sh taskrunner.sh 
Pinging google.com 4 times
..0.00user 0.00system 0:03.51elapsed 0%CPU (0avgtext+0avgdata 996maxresident)k 0inputs+16outputs (0major+338minor)pagefaults 0swaps

在终端中运行 COMMAND='ping google.com -c 4';EXECTIME=$({ TIMEFORMAT='%E';time $COMMAND >log; } 2>&1);echo $EXECTIME 按预期工作,即打印出时间(在我的情况下为 3.559 秒。)

我已经检查过了,/bin/sh 是指向dash 的符号链接。 (但这应该不是问题,因为我的脚本按照顶部的 shebang 在 /bin/bash 中运行。)

我希望在解决这个问题的同时学习,所以有解释的解决方案会很酷。谢谢。 :)

【问题讨论】:

    标签: bash time


    【解决方案1】:

    当您调用脚本时:

     sh scriptname
    

    脚本被传递给sh(在你的情况下为dash),它将忽略shebang行。 (在 shell 脚本中,shebang 是注释,因为它以 # 开头。这不是巧合。)

    Shebang 行仅对作为命令启动的命令进行解释,因为它们由系统的命令启动器而非 shell 解释。


    顺便说一句,您对time 的调用没有正确地将time 内置函数的输出与定时命令可能发送到stderr 的任何输出分开。我认为你会更好:

    EXECTIME=$({ TIMEFORMAT=%E; time $COMMAND >log.out 2>log.err; } 2>&1)
    

    但这还不够。尝试将命令放入字符串变量时,您将继续遇到标准问题,即它仅适用于非常简单的命令。请参阅Bash FAQ。或者看看这些答案:

    (或者可能有数百个其他类似的答案。)

    【讨论】:

    • 所以我检查了一下,使用bash script.sh 运行它可以正常工作。这是否意味着问题仅在于破折号?我也理解你关于重定向 stderr 的第二点。我会去做的。我阅读了您发布的链接,但我不明白。你的意思是我不应该将命令放入$COMMAND 或作为变量传递给task()?做类似事情的更好方法是什么?
    • @ZiaUrRehman: dash 没有内置的time,所以使用了/usr/bin/time,而/usr/bin/time 没有使用$TIMEFORMAT 环境变量。 (它使用$TIME 或命令行参数;请参阅man time。)通常,您应该chmod a+x 您的脚本,然后将它们作为./script.sh 运行。甚至./script。或者更好的是,将它们放在/usr/local/bin$PATH 中的其他目录中,然后以script 的形式运行它们。
    • @ZiaUrRehman:我为“如何通过脚本传递命令”问题添加了更多阅读材料。正如您将看到的,我(和许多其他人)更喜欢使用数组来做到这一点。
    • 太棒了。谢谢你的阅读材料。此外,这可能有点离题,但是 dash 与 bash?我已经阅读了一些关于它的材料,显然 Ubuntu 更喜欢 dash,因为它启动得更快,并且 Ubuntu 必须在启动时产生很多 shell。但这仍然不能明确哪个 终端应该用于您的日常脚本编写。我猜 bash 通常是首选。但是,如果 dash 比 bash 有一些优势,那么 可能 作为默认的 shebang 值得研究。
    • @ZiaUrRehman:对于日常脚本,请使用您喜欢的脚本语言。对我来说,bash 数组是必不可少的;我可以使用 ksh 或 zsh,但我习惯于 bash。对于以 root 身份运行的脚本,请使用您能找到的最受限制的 shell。对于用于跨平台通用分发的脚本,请使用 #!/bin/sh 并确保仅使用 Posix 标准结构,或使用特定但广泛可用的 shell,例如 bash 并记录依赖关系。
    猜你喜欢
    • 2017-11-28
    • 1970-01-01
    • 2021-05-14
    • 2023-03-26
    相关资源
    最近更新 更多