我有一个 Vagrant 盒子的设置脚本,我用来测量单个步骤time
。现在我想有条件地启用或禁用时间测量。
例如,以前的一行看起来像:
time (apt-get update > /tmp/last.log 2>&1)
现在我想我可以简单地做这样的事情:
MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""
$TIME (apt-get update > /tmp/last.log 2>&1)
但这是行不通的:
syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'
这里有什么问题?
答案1
有能力去时间一个子shell,你需要time
关键词,不是命令。
关键字time
是语言的一部分,只有在按字面输入并作为命令的第一个单词时才会被识别(在 的情况下ksh93
,下一个标记不以 开头-
)。更不用说,即使输入也"time"
不起作用$TIME
(并且将被视为对time
命令的调用)。
您可以在此处使用别名,这些别名会在执行另一轮解析之前展开(这样会让 shell 识别该time
关键字):
shopt -s expand_aliases
alias time_or_not=
TIMEFORMAT=%E
MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && alias time_or_not=time
time_or_not (apt-get update > /tmp/last.log 2>&1)
这time
关键词不接受选项(除了-p
in ),但可以使用变量 inbash
来设置格式。 (该部分也是特定的,其他外壳通常不需要)。TIMEFORMAT
bash
shopt
bash
答案2
虽然这alias
是一种方法,但这能也完成了eval
- 只是你不太想要eval
命令执行,而是想要eval
命令宣言。
我喜欢alias
es - 我一直使用它们,但我更喜欢函数 - 特别是它们处理参数的能力,并且它们不一定需要像alias
es 那样在命令位置进行扩展。
所以我想也许你也想尝试一下:
_time() if set -- "${IFS+IFS=\$2;}" "$IFS" "$@" && IFS='
'; then set -- "$1" "$2" "$*"; unset IFS
eval "$1 $TIME ${3#"$1"?"$2"?}"
fi
该$IFS
位主要是关于$*
.重要的( subshell bit )
是也是 shell 扩展的结果因此,为了将参数扩展为可解析的字符串,我使用"$*"
eval
"$@"
(顺便说一句,除非您确定所有参数都可以在空格上连接,否则不要这样做)。 args in 之间的分隔符"$*"
是 中的第一个字节$IFS
,因此在不确定其值的情况下继续操作可能会很危险。因此,该函数保存$IFS
,将其设置为\n
足够长的 ewline ,以将其set ... "$*"
放入,然后重置其值(如果以前有)。"$3"
unset
这是一个小演示:
TIME='set -x; time'
_time \( 'echo "$(echo any number of subshells)"' \
'command -V time' \
'hash time' \
\) 'set +x'
你看,我在其中的值中放置了两个命令$TIME
- 任何数字都可以 - 甚至没有 - 但请确保它被转义并正确引用 - 的参数也是如此_time()
。它们在执行时都会被连接成一个命令字符串 - 但每个 arg 都有自己的\n
ewline,因此它们可以相对容易地展开。或者,如果您愿意,您可以将它们全部集中在一起,并用\n
行号或分号或其他任何东西将它们分开。只要确保单个参数代表一个命令,当您调用它时,您可以放心地将其放在脚本中的单独一行上。\(
,例如就可以,只要它最终后面跟着\)
.基本上都是正常的东西。
当eval
得到上面的代码片段时,它看起来像:
+ eval 'IFS=$2;set -x; time (
echo "$(echo any number of subshells)"
command -V time
hash time
)
set +x'
而且,其结果看起来像......
输出
+++ echo any number of subshells
++ echo 'any number of subshells'
any number of subshells
++ command -V time
time is a shell keyword
++ hash time
bash: hash: time: not found
real 0m0.003s
user 0m0.000s
sys 0m0.000s
++ set +x
该hash
错误表明我没有/usr/bin/time
安装(因为我不)让command
我们知道正在运行的时间。尾随set +x
是执行的另一个命令后 time
(这是可能的)- 执行任何操作时务必小心输入命令eval
。