What is the internal processing of $* and $@

2019-08-13 03:06发布

问题:

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?

回答1:

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.