Bash while 条件

ada*_*o89 3 shell bash test

我有两个条件等待一段时间并检查目录中是否有多个文件。当这些条件之一为真时,必须执行循环,因此它是正常的 OR 逻辑语句。

预期的行为意味着如果时间经过或在目录中超过一个文件循环将结束。目前还在等待多个文件。有人能解释一下为什么我的 while 循环不能按预期工作吗?

i=1; while [ $i -le 10 ] || [ $( ls /opt/hosts/ | wc -l ) -lt 2 ]; do sleep 3 $(( i++ )); done
Run Code Online (Sandbox Code Playgroud)

不幸的是,我需要一行命令。我想知道为什么我的命令是无限循环为什么 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 ```
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 9

  • 你给出了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
Run Code Online (Sandbox Code Playgroud)

这会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
Run Code Online (Sandbox Code Playgroud)

这不会像set在子 shell 中运行那样破坏您现有的位置参数。它也更接近于你自己尝试过的事情类型。


作为“单线”:

i=1; while [ "$i" -ne 10 ]; do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; i=$(( i + 1 )); done
Run Code Online (Sandbox Code Playgroud)

或者,在 中使用“算术for循环” bash

for (( i=1; i<=10; i++ )); do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; done
Run Code Online (Sandbox Code Playgroud)

或者,使用分隔符上方的最后一段代码:

i=1; while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] ); do sleep 3; i=$(( i + 1 )); done
Run Code Online (Sandbox Code Playgroud)