Bash에서 숫자를 무한히 반복하는 방법은 무엇입니까?

Bash에서 숫자를 무한히 반복하는 방법은 무엇입니까?
  1. infinite_number_loopBash에서 실행하는 방법은 무엇입니까 ? ,다음과 같습니다:

    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_loopBash에서 실행하는 방법은 무엇입니까 ?

가장 간단한 방법 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

시간대의 영향도 받습니다.

산술 메모

쉘 정수의 최대값은 i가 2보다 작고 63으로 증가합니다.

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

다음과 같이 10진수와 16진수 표현을 얻을 수 있습니다.

$ 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

관련 정보