如何在bash中无限循环数字?

如何在bash中无限循环数字?
  1. 如何infinite_number_loop在bash中运行a? ,如下所示:

    for i in infinite_number_statement
        do date +%Y-%m-%d -d "$i day ago" 2>&1 > /dev/null
            if [ $? -ne 0 ]
               then echo $i
            fi
    done
    
  2. 如果我在本地计算机的终端中运行此循环,是否有任何问题? (我用循环尝试了一个大的随机数范围for,并被挂起一次。)

答案1

如何infinite_number_loop在bash中运行a?

最简单的方法while :; do ... done::

let i=0
while :; do
    let i++
    date +%Y-%m-%d -d "$i day ago" >/dev/null 2>&1 || { echo $i && exit 1; }
done

如果我在本地计算机的终端中运行此循环,是否有任何问题?

直到你意识到你在这件事上浪费了太多时间。

答案2

不是无限循环,而是找到日期实际限制的更好方法:

#!/bin/bash

j=$((1<<61))
i=0
while ((j>0)); do
    if date +'%Y-%m-%d' -d "$((i+j)) days ago" >/dev/null 2>&1; then
    ((i+=j)) ; # printf 'running i %d 0x%x\n' "$i"{,}
    else
    ((j>>=1)); # printf 'new     j %d 0x%x\n' "$j"{,}
    fi
    ((k++))
    # ((k%10)) || printf 'still running %d 0x%x %d %d' "$i"{,} "$j" "$k"
done
printf "final value of limit %d 0x%x in %d loops\n" "$i"{,} "$k"

这将发现日期限制为:

final value of limit 2147483649 0x80000001 in 64 loops

删除评论字符#看看这是如何做到的。

它不是 32 位数字。

这似乎接近于 32 位数字:

$ printf '%d\n%d\n' "$(( (1<<31) + 1 ))" "0x80000001"
2147483649
2147483649

事实上,就是2**31+该月的天数。
如果我们尝试使用 12 月的最后一天(更改上面脚本中的第 5 行):

date +'%Y-%m-%d' -d "2017-12-31 $((i+j)) days ago"

我们得到:

final value of limit 2147483679 0x8000001f in 68 loops

上面是 31 2**31

$ printf '%d\n%d\n' "$(( (2**31) + 31 ))" "0x8000001f"
2147483679
2147483679

它还受时区的影响。

算术笔记

shell 整数的最大值是 i 小于 2,提高到 63:

$ echo $(( (2**63) - 1 ))
9223372036854775807

我们可以通过以下方式获得十进制和十六进制表示:

$ printf '%d %x\n' "$(( (2**63) - 1 ))"{,}
9223372036854775807 7fffffffffffffff

这是 64 位有符号整数可表示的最大数字(当然,如果您的系统是 64 位)。下一个数字(只需加一)将环绕(溢出)为负数:

$ echo $(( (2**63) ))
-9223372036854775808

$ printf '%d %x\n' "$(( (2**63) ))"{,} 
-9223372036854775808 8000000000000000

这恰好是有符号 64 位整数的最大负数。

但获得相同结果的更快方法是使用左移,其作用与将数字乘以 2 相同:

$ printf '%d %x\n' "$(( (1<<63) - 1 ))"{,}
9223372036854775807 7fffffffffffffff

相关内容