声明变量时防止运行命令替换

声明变量时防止运行命令替换

所以我最近注意到,当使用命令替换声明变量时,可以这样说:

var=$(echo "this is running" > test; cat test)

然后它将要run (将创建文件test),即使我还没有(技术上)调用它,我希望这样:

var=$(echo "this is running" > test; cat test)
echo "$var" # is where i would "normally" call the variable

在变量中声明命令替换时,如何防止命令替换实际运行,因此它实际上只是跑步当我调用所述变量时?

PS:很清楚这是一个不好的例子,但它很好地证明了我的意思,尽管“无用的猫”和“无用的回声”......

答案1

听起来您想要一个其内容是动态生成的变量。

bash不支持ksh93的学科,或 zsh 的动态命名目录或 mksh 的价值替代这会让事情变得更容易,但是你可以使用这种 hack,使用 namerefs:

var_generator() { date --iso-8601=ns; }
var_history=()
typeset -n var='var_history[
  ${##${var_history[${#var_history[@]}]=$(var_generator)}},${#var_history[@]}-1
]'

这里var定义为对数组元素的引用$var_history,利用数组索引动态计算的事实并允许运行任意代码(这里用于运行函数var_generator并将其输出分配给数组的新元素)。

然后:

bash-5.1$ echo "$var"
2021-03-23T13:36:43,243211696+00:00
bash-5.1$ echo "$var"
2021-03-23T13:36:45,517726619+00:00

这听起来有点太复杂了,尽管你可以$(var_generator)在这里使用。不过,一个优点是您仍然可以做类似${var#pattern}while bash(与zsh) won't let you do类似的事情${$(cmd)#pattern}

答案2

它运行是因为你确实调用了它。 Shell 扩展就在那里发生,这与 Make 中的变量不同,后者通常是延迟计算的。如果这样做var='$(...)',命令替换将不会运行,但以后也很难运行它。这类似于某些东西如何复制当时foo=$bar的值,而不是稍后在最终使用时查看它。barfoo

简单的替代方法是使用函数。例如,这应该打印两个相距大约 5 秒的日期:

getdate() {
    date +"%F %T"
}
a=$(getdate)
sleep 5
b=$(getdate)
echo "$a $b"

使用函数的缺点是可用于参数扩展的字符串操作不可用。你不能${(getdate)% *}只得到输出的第一部分,你必须这样做foo=$(getdate); foo=${foo% *};

相关内容