Strangeness in shell

Guy Harris guy at auspex.auspex.com
Tue Jul 25 04:38:02 AEST 1989


> Ummm... I had always learned (obviously flawed) that the single quotes 
>prevented expansion of ANYTHING....

They do.  That's why the statement

	x='*z'

assigns the string "*z" to the variable "x".

Note, though, that the string is "*z", not "'*z'" - in other words, the
quotes are gone.  (The quotes in "*z" in the statment

	...assigns the string "*z" to the variable "x".

mark the boundaries of the string; they are *not* part of the string. 
In other words, the variable "x" has a two-character string as its
value, the first character of which is '*' and the second character of
which is 'z'.)

This means that the statement

	echo ${x}

is expanded to

	echo *z

by substituting the value of the variable "x" for the "${x}".

*After* the substitution is performed, the command is cut up into
tokens; the two tokens in this case are "echo" and "*z".  Then the
tokens have file-name expansion performed on them, so that "*z" expands
either to a list of all the files whose names end with "z", if there are
any such files, or to a list containing only "*z", if there aren't any
such files.

(All this is covered in the SH(1) man page in SunOS, and I think that's
pretty much derived from the S5 man page, so it should be there as well.
It takes a bit of searching to find the pieces of the description.)

>Even if this is not the case, why does it behave differently in the two
>cases?

Because the "tokenization" is done between the variable expansion and
the file name expansion.  Thus,

	x='* z'

assigns the three-character string "* z" to the variable "x", just as

	x='*z'

assigned the two-character string "*z" to "x".  The statement

	echo ${x}

is then expanded into

	echo * z

when the value of "x" is substituted into it.  The quotes are not
preserved, remember, so this is then broken into *three* tokens -
"echo", "*", and "z".  The first and third tokens expand to themselves
when file-name expansion is performed; the second token expands to a
list of all files in the current directory (except for those whose name
begins with ".").

Now if you want the "echo" to literally echo the value of "x", you
should do

	echo "${x}"		# or just echo "$x"

because double-quotes prevent file-name expansion but do *not* prevent
variable-name expansion.  If you want "echo" to echo the string "${x}",
rather than the value of the variable "x", do

	echo '${x}'

>If you have no files ending in  z  , then why does it not return a null 
>string for the '*z' version ?

Because that's the way the Bourne shell works.  If a filename pattern
doesn't match any file names, it is left unchanged, not expanded to a
null string or a null list.



More information about the Comp.unix.questions mailing list