Why do you need the shift?
As mentioned elsewhere, a counter is the usual solution.
If shift isn't required for some other reason you didn't include, here's another for loop implementation.
$: set one two three; declare -i i=0; for o in "$@"; do i+=1; echo "#$i: $o"; done
#1: one
#2: two
#3: three
And of course, as Jetchisel demonstrated, if you're using the default arguments you can just skip the in "$@" bit...
$: set one two three; declare -i i=0; for o; do i+=1; echo "#$i: $o"; done
#1: one
#2: two
#3: three
If you do require the shift, and/or prefer the while -
$: set one two three; declare -i i=0; while(($#)); do i+=1; echo "#$i: $1"; shift; done
#1: one
#2: two
#3: three
Make sure you declare that counter as an integer, or you'll have to take other steps to get the result you want...
$: set one two three; i=0; while(($#)); do i+=1; echo "#$i: $1"; shift; done # oops!
#01: one
#011: two
#0111: three
$: set one two three; i=0; while(($# && ++i)); do echo "#$i: $1"; shift; done # corrected
#1: one
#2: two
#3: three
There are a million ways to do this.
Here's a less efficient one just for the fun of it. :)
$: seq $# | while read -r i; do echo "#$i: ${!i}"; done
#1: one
#2: two
#3: three
seq, tryfor i in $(seq $#); do echo "#$i: ${!i}"; done.shiftin a loop? Any other constraints on the kind of solution that'd be acceptable?