所以我最近注意到,当使用命令替换声明变量时,可以这样说:
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
的值,而不是稍后在最终使用时查看它。bar
foo
简单的替代方法是使用函数。例如,这应该打印两个相距大约 5 秒的日期:
getdate() {
date +"%F %T"
}
a=$(getdate)
sleep 5
b=$(getdate)
echo "$a $b"
使用函数的缺点是可用于参数扩展的字符串操作不可用。你不能${(getdate)% *}
只得到输出的第一部分,你必须这样做foo=$(getdate); foo=${foo% *};