Csh substitution

liberte at uiucdcs.UUCP liberte at uiucdcs.UUCP
Wed Jan 30 15:07:00 AEST 1985


Here is a summary of solutions and other observations resulting from my
recent query.

My problem was how to inhibit filename expansion of a variable value inside
of an embedded command.  This is a more interesting problem than even I
thought.  There seem to be some misunderstandings as well as some possible
bugs in csh that compounded the confusion.

First the solutions.

Of course, one solution I mentioned previously is to simply set noglob
before the critical code.  No double quotes (") are needed thereafter but
they hold things together (set would try to set later items as variables).

	set noglob
	set x = "ls .*"
	set z = `echo $x`
	echo "$z"	# The echo output here is not the goal.
			# The goal is to assign "ls .*" to z by way of
			# the embedded command.

This is non-obvious only because the name "noglob" does not imply, in my
mind, a filename expansion inhibitor.  And how does "noglob" relate to the
`glob` builtin command?

A second, less obvious solution is to use double quotes around the
embedded command in addition to double quoting the variable expansion inside
the embedded command.  To do this, you have to first assign the command
string to a variable ($y) and use that value in the embedded command:

	set x = "ls .*"		# filename expansion never occurs here.
	set y = 'echo "$x"'
or	set y = 'echo $x:q'
	set z = "`$y`"

This does work.  (The advantage of this method is that some variables may be
expanded while others are not - within the same embedded command.)  It is
important to realize that the filename expansion IS, in fact, inhibited by
quoting the variable within the embedded command, but then the RESULT of the
embedded command is then filename expanded, unless it also is quoted.

What follows are a few more interesting things that dont work.

--------------------------

You cannot simply insert the command string with the quoted variable(s) into
this "double quoted embedded command".  The variable is expanded anyway
because it is in double quotes no matter what other quotes it is in, and then
the filename expansion is applied by the embedded command (I think).

	set z = "`echo $x:q`"		# .* is expanded anyway
or	set z = "`echo "$x"`"		# This is accepted - but it expands
or	set z = "`echo ""$x""`"		# Same result
or	set z = "`echo """$x"""`"	# Getting carried away. Unmatched `.
or	set z = "`echo \"$x\"`"		# Unmatched `.
or the suggestion from Ian! D. Allen below.

One other method I discovered, but dont understand, requires three sets
of quotes on the $x.  Anything less and the .* is expanded:

	set z = "`echo "\$x:q"`"

This doesnt work because it is too complicated.


> From ihnp4!watmath!idallen Sun Jan 13 00:04:28 1985
>  ...
> The problem is the presence of special filename characters in the output
> of the substitution.  You might think you should try to quote them.  You
> might have thought you could echo quotes to protect the >>ls .*<< before
> it was assigned to y:
> 
> > set x = "ls .*"
> > set y = `echo '"'"$x"'"'`
> 
> You would think the output of the command substitution should be
> >>"ls .*"<<, and indeed it almost is, but those quotes aren't going to
> behave the way you expect.   The contents of Y after the above is
> >>"ls<<.  No typo -- the first character is a quote and only the LS is
> left.  Why?  Where did the filenames go?
> 
> C Shell Funny #237: Quotes have no meaning in the output from variable
> or command substitution.  They behave just like ordinary characters.
> 
	{Unless they end up inside embedded commands - where they are
	 then processed anew. - dan}

> C Shell Corollary #237-A: Filename expansion is always done in the
> output of variable or command substitution, because you can't use quotes
> to protect the special characters.
> 
	{You can use quotes as I did.}

> C Shell Funny #238: You get no error message if a filename expansion
> in the output of a command substitution fails, that is, "No match"
> never appears, unless the entire output of the substitution is null.
> 
> You now know what happened.  >>"ls .*"<< was the output of the
> command substitution, but quotes aren't special, no file name
> ended in a quote, so >>.*"<< expanded to nothing, leaving only >>"ls<<.
> Since >>"ls<< isn't null, no error message appeared.
> 
...
> I found all this nonsense hard to understand, so the Waterloo version
> of the C Shell automatically "quotes" filename characters appearing in
> the output of command substitution.  My philosophy is -- since the
> thing isn't being properly parsed (i.e. because quotes aren't doing
> their job), it shouldn't be filename expanded either.
> 
> To be consistent, I should also quote special characters in the output
> of variable substitution, but I haven't had the courage to do it yet.
> (Mabe I'll do it today...)
> 

Thanks for everyones efforts.

I have some other peculiar quoting phenomenon I may present later.
If you come across something interesting, let me know.  

I would also like to create, or otherwise procure, a diagram of the parsing
done by csh - at least history, jobnames (%n), aliases, variables, quotes
(single, double, and command), and filename expansion.  Send ideas.

Daniel LaLiberte
ihnp4!uiucdcs!liberte
liberte at uiucdcs.Uiuc.ARPA
U of Illinois, Urbana-Champaign, 
Dept of Computer Science
(217) 333-8426



More information about the Comp.unix mailing list