Why is $@ different from most other variables in bash?

The $@ variable seems to support quoting around its arguments, so that, for example:

$ function foo { for i in " $@ "; do echo $i; done } $ foo herp "hello world" derp herp hello world derp 

I also know that bash arrays work the same way:

 $ a=(herp "hello world" derp) $ for i in "${a[@]}"; do echo $i; done herp hello world derp 

What happens to such variables? Especially when I add something to the quote like "duck $ {a [@]} goose". If its space is not divided, what is it?

+4
source share
1 answer

Usually double quotes in Bash mean "do everything between quotes in one word, even if it has delimiters". But, as you have noticed, $@ behaves differently when in double quotes. This is actually parsing that goes back to Bash's predecessor, the Bourne shell, and this particular behavior only applies to this particular variable.

Without this hack (I use this term because it seems inconsistent in terms of language, although it is very useful), it will be difficult for the shell of the script to pass an array of arguments to any other command that wants the same arguments. Some of these arguments may contain spaces in them, but how do you pass them to another command without a shell, either combining them as one big word, or rewriting the list and separating the arguments with a space?

Well, you can pass an array of arguments, and the Bourne shell really only has one array, represented by $@ , the number of elements of which is $# and whose elements are $1 , $2 , etc., the so-called positional parameters.

Example. Suppose you have three files in the current directory named one , two and thuh ree (the third file has a space in the name). You can initialize the array (that is, you can set the positional parameters) as file names in the current directory, for example:

 set -- * 

Now the $@ array contains the file names, and this loop:

 for FILE in " $@ "; do echo "$FILE" done 

will produce this result:

 one two thuh ree 

because $ 1 = "one", $ 2 = "two", and $ 3 = "thuh ree" and " $@ " leaves the elements intact. Thanks, parsing hacking. If you leave quotes around $@ , the shell will smooth and re-parse the array, so you get this output:

 one two thuh ree 

In Bourne, this behavior does not apply to other variables that are not arrays. But Bash allows you to create other arrays, and even allows you to apply the old parsing to them using the special syntax "${ARRAYNAME[@]}" , whose at sign almost resembles Mr. Bourne.

Oh, and about your last example, what should the shell do with "pre $@ post" , where the decomposition takes place inside the word? Recent versions of Bash save the array and also add text before $@ to the first element of the array and add text to the last element:

 pre one two thuh ree post 
+10
source

All Articles