2
  1. How to run a infinite_number_loop in bash? , like below :

    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. If I run this loop in terminal in my local machine, is there any issue? (I tried a big random number range with for loop and got hung once.)

4
  • in some recent testing I got my bash shell up to 9223372036854775807
    – Jeff Schaller
    Feb 28, 2017 at 20:20
  • 1
    Can you proofread your question, and edit accordingly. The only bit that makes sense to me is the line that says I have wasted my time reading everything up to here. Feb 28, 2017 at 21:33
  • unfortunately a for loop with a truly infinite_number_statement would be impossible, because bash waits for the statement to terminate before starting the actual loop.
    – Sam
    Oct 3, 2018 at 15:14
  • you can see this with yes | sed -n '=' for example
    – Sam
    Oct 3, 2018 at 15:15

2 Answers 2

5

How to run a infinite_number_loop in bash?

The easy way: 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

If I run this loop in terminal in my local machine, is there any issue?

Not until you realize you wasted too much time on this.

1
  • Thanks @sato , that worked. BTW something is gained every second, no regrets in "wasting" time like this ;)
    – prado
    Feb 28, 2017 at 20:45
1

Not an infinite loop, but a better way to find the actual limit of date:

#!/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"

That will find the limit of date to be:

final value of limit 2147483649 0x80000001 in 64 loops

Remove the comment character # to see how that is done.

It is not a 32 bit number.

That seem to be close to a 32 bit number:

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

In fact, is 2**31 + the day number of the month.
If we try with the last day in December (change line 5 in the script above):

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

We get:

final value of limit 2147483679 0x8000001f in 68 loops

That's 31 above 2**31:

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

It is also affected by the time zone.

Arithmetic notes

The max value for a shell integer is i less than 2 raised to 63:

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

We can get the decimal and hexadecimal representation with:

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

That's the maximum number representable in a signed integer of 64 bits (if your system is 64 bits, of course). The next number (just add one) will wrap around (overflow) to a negative number:

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

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

Which happens to be the most negative number for signed 64 bit integer.

But a faster way to get the same result is using left shift, which does the same as multiplying a number by two:

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .