我有两个条件等待一段时间并检查目录中是否有多个文件。当这些条件之一为真时,必须执行循环,因此它是正常的 OR 逻辑语句。
预期的行为意味着如果时间经过或目录中的时间超过一个文件循环就会结束。目前仍在等待不止一份文件。有人能解释一下为什么我的 while 循环不能按预期工作吗?
i=1; while [ $i -le 10 ] || [ $( ls /opt/hosts/ | wc -l ) -lt 2 ]; do sleep 3 $(( i++ )); done
不幸的是我需要一行命令。我想知道为什么我的命令是无限循环为什么 OR 不能像应该那样工作:(我将第一个条件更改为 3)
+ echo host_name
+ i=1
+ '[' 1 -le 2 ']'
+ sleep 1 1
+ '[' 2 -le 2 ']'
+ sleep 1 2
+ '[' 3 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 3
+ '[' 4 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 4
+ '[' 5 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 5 ```
答案1
你给出了
sleep
两个参数,3
并且$(( i++ ))
。对于 GNU 工具,这意味着循环在每次迭代中休眠的秒数会增加。在非 GNU 系统上,您会收到来自 的错误sleep
。你的循环将始终运行至少10 次,具体取决于您编写测试的方式。您的测试显示“迭代
$i
小于或等于 10”。一旦$i
达到10,测试的其他部分就会生效。您可能需要在这里进行逻辑 AND 测试,而不是 OR。您不应该使用
ls | wc -l
来计算目录中的文件数。在某些(尽管是病态的)情况下,这会给出错误的结果。
反而:
i=1
while [ "$i" -ne 10 ]; do
set -- /opt/hosts/*
if [ "$#" -ge 2 ]; then
break
fi
sleep 3 # or, to sleep longer and longer: sleep "$(( 3 + i ))"
i=$(( i + 1 ))
done
这i
在每次迭代中都会适当地递增,并且还使用更安全的方法来计算目录中的名称数量/opt/hosts
(通过扩展*
目录中的 glob 并计算它扩展为的名称数量)。只要名称数量为两个或更多,或者$i
达到值 10,循环就会退出。
循环后,如果$i
为10,则文件未能实现。
如果您需要保留位置参数(这些参数将被命令覆盖set
),请使用 将 glob 展开为数组names=( /opt/hosts/* )
,然后使用"${#names[@]}"
来获取该数组的长度,而不是使用"$#"
。
你也可以写成
i=1
while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] )
do
sleep 3
i=$(( i + 1 ))
done
这不会破坏您set
在子 shell 中运行的现有位置参数。它也更接近于你自己尝试过的事情类型。
作为“一行”:
i=1; while [ "$i" -ne 10 ]; do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; i=$(( i + 1 )); done
或者,使用“算术for
循环” bash
:
for (( i=1; i<=10; i++ )); do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; done
或者,使用分隔线上方的最后一段代码:
i=1; while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] ); do sleep 3; i=$(( i + 1 )); done