Actually, I am fully understand the use of $* and $@.
For example, if I run the script using: my_script *
Then, for ONE_FILE in $@ will really get each file into ONE_FILE for processing.
Even there is space(s) in the filenames, ONE_FILE will get the correct filename.
If, however, using for ONE_FILE in $*, the story is different.
I think you guys understand the difference and I do not need to go further.
Now, what I am interested is HOW.
How the KornShell (ksh) interprets the my_scrpt *
and then pass the filenames into $@ correctly
and pass the filenames into $*.
For example, when the ksh see my_script *
, does it put the filenames one by one into an array,
and then put the array[1][2][3]... into $@ for processing ?
And, when seeing $*, does it just concat
filename1+space+filename2+space+... ?
I know that this may relate more to the internal coding of ksh.
Any insight?
For example, when the korn shell see my_script *, does it put the filenames one by one into an array,
and then put the array[1][2][3]... into $@ for processing ?
And, when seeing $*, does it just concat
filename1+space+filename2+space+... ?
Yes, pretty much.
One important thing to realize here are that there are two separate processes involved: the calling shell, which expands my_script *
into myscript arg1 arg2 arg3
and the subprocess which gets the array of arguments. If that subprocess is ksh
(or sh
, bash
, or a similar shell) then $*
is just syntax for "get argv[1...] as a concatenated string" while $@
is syntax for "get argv[1...] as an array". It's also important to note that $*
and $@
are only meaningfully different when quoted.
In bash, a cousin of ksh, this idea of array variables has actually been generalized. (Perhaps ksh has done this too -- I haven't used ksh for about a decade...)
In bash, this creates an array of 3 elements called a
. Note that the first element contains a space:
[~]$ a=("foo bar" baz quux)
[~]$ for i in ${a[*]}; do echo $i; done
foo
bar
baz
quux
[~]$ for i in ${a[@]}; do echo $i; done
foo
bar
baz
quux
[~]$ for i in "${a[*]}"; do echo $i; done
foo bar baz quux
[~]$ for i in "${a[@]}"; do echo $i; done
foo bar
baz
quux
As you can see from the example, "${a[*]}"
concatenates the array while "${a[@]}"
actually gives you the individual elements.