roaima's answer answers the question that you actually asked:
Q: What is the difference between these two code blocks?
Why do they give different output?
A: The first loop is iterating over the command line arguments;
the second one is iterating over the argument numbers (indices).
... although I presume that you would have figured that much out
for yourself in another six to eight minutes — it's kind-of obvious.
You probably want the second program to do something like
echo $$i # This doesn't do what you want.
to display the argument that is indexed by the number
that is stored in variable i
(and referenced as $i
).
As noted in the comment, that doesn't do what you want.
(It does do something;
I encourage you to experiment and figure out what it does.)
But this is close to something that does work:
eval echo \$$i # Don't do this.
or, equivalently,
eval echo '$'"$i" # Don't do this.
These commands
- get the value of
i
(one of the numbers 1, 2, 3, ...)
- stick a
$
in front of it, forming $1
, $2
, $3
, etc.
- use the
eval
command to say, "take this command line
that I've just constructed, and evaluate it as if I had typed it.
So that would have the effect of executing
echo $1
echo $2
echo $3
︙
But, as the comments suggest, you should try to avoid this.
eval
can be dangerous if the input is anything other than plain words.
Search this site; you'll find plenty of explanations of that.
But there is a fairly safe way to get the second program
to do the same thing the first one does: change
echo $i
to
echo ${!i}
OK, first of all, ${i}
is pretty much the same as $i
.
The !
gives you an effect similar to that of the eval
command —
${!x}
looks up the value of x
(i.e., $x
or ${x}
)
and uses that as the name of the variable to look up.
So, if x=foo
, then ${!x}
is the same as $foo
.
The above code does the same thing with i
,
fetching the parameter whose name is the value of i
.
By the way, you should always quote all references to shell variables
(e.g., "$i"
, "$#"
, "$args"
, "${i}"
and "${!i}"
)
unless you have a good reason not to,
and you’re sure you know what you’re doing.
echo $i
byecho $i $1; shift
to get more confused or enlightened.while (( "$#" )); do echo $1; shift; done
It served its purpose; confusion. I would still like to know why Block #2 does not produce the same output as Block #1 :)i
and assigning an integer index to it; in #1, the shell is implicitly assigning each positional parameter in turn toi
. See thefor name [ [ in [ word ... ] ] ; ] do list ; done
construct in theCompound commands
section ofman bash
.