这是我的脚本的一部分:
#!/bin/sh
n=1
echo "How many repetitions to run (0 = no limit)?"
read reps
if [ $reps = 0 ]; then
while="true"
else
while="[ $n -lt $((reps+1)) ]"
fi
echo "How much off-time in-between reps (in minutes)?"
read time
pwr_init
while $while; do
echo "* Sending power pulse $n"
pwr_normal
t=$time
echo "* Waiting for next power on"
while [ $t -gt 0 ]; do
echo " $t min until next power on"; sleep 60
t=$((t-1))
done
n=$((n+1))
done
while
除了我正在进行的第一个循环之外,一切都完全按照我的需要进行。每当$while
调用变量时,我希望 shell 扩展并检查第一个语句中定义的当时的变量if
。
我只能让 shell 在第一个语句时扩展变量if
,但随后我得到的行为是true
因为比较器始终为 true,并且在$n
递增时永远不会改变,因为该$while
变量已经在第一个if
语句期间扩展了所有内容。
我尝试过类似的方法${!while}
以及单引号和双引号的各种组合,但没有运气。我通常会收到类似$n is a bad number
或 的错误bad substitution
。
现在我唯一能想到的就是在更多函数中添加更多语句,以便每次都if
检查这一行并将其回显到语句中。while
我必须相信有更好的方法来做到这一点,不过,我只是很难弄清楚(并且也找到了正确的关键字来在线搜索)。
在调试时,我使用set -x
,并且可以看到比较器字符串正在以此处编写脚本的方式正确评估,但正如我提到的,它在$n
递增时永远不会更新自身。
有没有人有这种类型的替代技巧,可以让生活变得更轻松一点?非常感谢任何可以对这个奇怪的变量扩展难题给出的见解!
注意 1:pwr_init
和pwr_normal
是完整脚本中其他地方定义的函数。
注意 2:记下 shebang,它必须符合 POSIX 标准。我无法使用任何花哨的 bash 特定技术。
编辑:让它像我需要的那样发挥作用比我想象的要简单,我把我添加的内容放在下面。不过,我将这个问题留待解决,因为如果知道这种类型的变量扩展是否可以完成,那就太好了。
新脚本的check
函数包含在if
语句中:
#!/bin/sh
n=1
echo "How many repetitions to run (0 = no limit)?"
read reps
count=$((reps+1))
check() {
if [ $reps = 0 ]; then
while="true"
else
while="[ $n -lt $count ]"
fi
}
echo "How much off-time in-between reps (in minutes)?"
read time
pwr_init
while $while; do
echo "* Sending power pulse $n"
pwr_normal
t=$time
echo "* Waiting for next power on"
while [ $t -gt 0 ]; do
echo " $t min until next power on"; sleep 60
t=$((t-1))
done
n=$((n+1))
check
done
答案1
非常简单的解决方案:要运行“无休止”,只需将限制设置为某个非常大的数字即可。一个 32 位整数可以容纳最多 4294967296 的数字。考虑到符号位并向下舍入,我们可以假设我们至少可以计数到 2000000000。由于您在计数之间至少睡了一分钟,所以这是可行的长达,哦,大约4000年。
所以就这样做:
if [ "$reps" = 0 ]; then
reps=2000000000
fi
并将条件硬连线为
while [ "$n" -le "$reps" ]; do ...
(如果您运行的是 64 位系统,则可以计算得更高。但这并不重要。如果您运行的是 16 位系统,那么您也可能会在其他方面被搞砸。)
简单的解决方案:只需创建一个函数来检查是否reps
为零或n
小于reps
。
keep_going() {
[ "$reps" = 0 ] && return 0
[ "$n" -le "$reps" ]
}
然后提出条件
while keep_going; do ...
是的,您每次都会调用一个函数。不,这没关系,因为您最多每分钟只调用一次。(如果您确实关心速度,则不应该使用 shell 来执行此操作。)
您正在寻找的解决方案:使用eval
。在对 的赋值中使用双引号while="[ $n -lt $count ]"
,$n
和都$count
将立即展开。您需要的是在赋值中使用单引号:while='[ $n -lt $count ]'
然后运行字符串eval
以扩展其中的变量。
while='[ $n -lt $count ]'
while eval "$while" ; do ...
答案2
您可以尝试定义不同的函数:
if [ $reps -eq 0 ]; then
while_test() { true; }
else
while_test() { test $1 -lt $((reps+1)); }
fi
然后
while while_test $n; do
您可以eval
在 POSIX shell 中使用来处理变量中的条件:
$ cond='[ $n -lt $reps ]'
$ reps=5
$ n=4
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n < reps
$ n=5
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n >= reps
确保条件是用单引号定义的,这样变量就不会过早扩展。