wmartin@almsa-1.arpa (Will Martin -- AMXAL-RI) (11/30/88)
I have a query about filename generation/wildcard expansion. I have looked in the man pages and in several UNIX books, and talked about this locally, but haven't found an explanation. I've tested it on both Sys V (on a Sperry Unisys) and 4.3 BSD (on a VAX 750). It seems to be a consistent difference between sh and csh. Given the situation where you are trying to redirect output to a directory in some path structure, where you do have write access, but want to save time in typing: Say my login directory is /usr/wm. I also own a directory in another filesystem: "/data/save-backups". I am sitting in /usr/wm and want to put some data into that other directory, but want to avoid typing out "save-backups" all the time. There is nothing else under /data that begins with "sa". So I do this: cat foo > /data/sa*/bar or cat foo >> /data/sa*/bar Under "sh", no matter whether or not "bar" exists in that destination directory, this won't work. I get the response: sh: /data/sa*/bar: cannot create The shell will not expand that "*" to fill out the directory name. I have to type out the full "/data/save-backups/bar" pathname to get it to work. Under "csh", if "bar" doesn't exist, I get: "/data/sa*/bar: No match", but, if "bar" DOES exist, and I do either: cat foo > /data/sa*/bar or cat foo >> /data/sa*/bar it will work OK! So "csh" expands the wildcard * correctly in this case. My query: Is this just a case where "sh" was broken and "csh" fixed it? Or is there something else going on here? And, if "csh" lets this work as shown, why does it NOT work when creating the file initially? What I don't understand is why the expansion doesn't work under "sh". You are sitting at the shell at this point. If the command was an "ls", the "*" WOULD expand OK. Why doesn't it expand in this case? Puzzled, Will Martin "wmartin@almsa-1.arpa"
logan@vsedev.VSE.COM (James Logan III) (11/30/88)
In article <17661@adm.BRL.MIL> wmartin@almsa-1.arpa (Will Martin -- AMXAL-RI) writes:
#I have a query about filename generation/wildcard expansion. I have looked
#in the man pages and in several UNIX books, and talked about this locally,
#but haven't found an explanation. I've tested it on both Sys V (on a Sperry
#Unisys) and 4.3 BSD (on a VAX 750). It seems to be a consistent difference
#between sh and csh.
#
#Given the situation where you are trying to redirect output to a directory
#in some path structure, where you do have write access, but want to save
#time in typing:
#
#Say my login directory is /usr/wm. I also own a directory in another filesystem:
#"/data/save-backups". I am sitting in /usr/wm and want to put some data into
#that other directory, but want to avoid typing out "save-backups" all the time.
#There is nothing else under /data that begins with "sa".
#
#So I do this:
#
#cat foo > /data/sa*/bar or cat foo >> /data/sa*/bar
#
#Under "sh", no matter whether or not "bar" exists in that destination
#directory, this won't work. I get the response:
#
#sh: /data/sa*/bar: cannot create
#
#The shell will not expand that "*" to fill out the directory name. I have to
#type out the full "/data/save-backups/bar" pathname to get it to work.
#
Every version of the Bourne shell that I have seen does not
interpret the filename expansion characters after a redirection
symbol. I believe this is to prevent
cat foobar >/data/sa*/bar
from expanding into
cat foobar >/data/sally/bar /data/sandy/bar
which would effectively be the same as
cat foobar /data/sandy/bar >/data/sally/bar
which was probably not intended.
The Korn shell gets this right by expanding the wildcard only if one
file matches. If more than one file matches, the wildcard is used
literally.
-Jim
--
Jim Logan logan@vsedev.vse.com
(703) 892-0002 uucp: ..!uunet!vsedev!logan
inet: logan%vsedev.vse.com@uunet.uu.net
ok@quintus.uucp (Richard A. O'Keefe) (11/30/88)
In article <17661@adm.BRL.MIL> wmartin@almsa-1.arpa (Will Martin -- AMXAL-RI) writes: >Under "csh", if "bar" doesn't exist, I get: "/data/sa*/bar: No match", >but, if "bar" DOES exist, and I do either: > >cat foo > /data/sa*/bar or cat foo >> /data/sa*/bar > >it will work OK! So "csh" expands the wildcard * correctly in this case. > >And, if "csh" lets this work >as shown, why does it NOT work when creating the file initially? When you give a wildcard pattern in Csh, there has to be at least one thing in the file system which matches the complete pattern. Suppose you have an empty directory /data/savewhatsit/ and no other directories matching /data/sa* . Where then is there anything that matches the **whole** pattern /data/sa*/bar ? If you just want to save yourself a lot of typing, use a shell variable: Csh: set sa=/data/sa* echo works first time >$sa/bar Sh: sa=`echo /data/sa*` echo works first time >$sa/bar Your message was /usr/spool/news/comp/unix/questions/7149 here. In the Bourne shell, I did $ NEWS=/usr/spool/news $ cd $NEWS/comp/unix $ echo que*/7149 $ echo $NEWS/co*/un*/que*/7149 and both echos worked. This was on a Sequent, and the test worked in both the "att" and the "ucb" universes. For some real fun, I went to my home directory and made a subdirectory zabbo containing a file fred. $ echo trouble >zab*/fred zab*/fred: cannot create $ x=zab*/fred $ echo $x zabbo/fred $ echo real trouble >$x zab*/fred: cannot create Let's get this last one out of the way first. $ echo "$x" zab*/fred We see from this that when a variable is assigned a value, that value is not wild-card expanded ("globbed"). But if you use the value of the variable later in a context where globbing is done, the value will be globbed then. That's why I wrote sa=`echo /data/sa*` above. What about ">zab*/fred"? Why didn't that work? Well, you have to read the Sh manual page with extreme attention to detail. Several sorts of "evaluation" happen to a command line. Command SUBSTITUTION `command` is called and the output substituted Parameter SUBSTITUTION $thingies are replaced by their values File Name GENERATION "globbing", "wild-cards". The manual page says clearly that this happens after command and parameter substitution and blank interpretation. Now when we come to input/output redirection, we are told about <word >word >>word and so on that "SUBSTITUTION" happens to the word before it is used. That's *all* that happens; file name generation (globbing, wild-card processing) is not done, and blank interpretation is not done either. $ y="BIG trouble" $ echo $y >$y $ ls BIG trouble fred $ ls $y BIG not found trouble not found $ rm "$y" You can see why the Bourne shell works this way: before command and parameter substitution the "word" is *one* thing; blank interpretation and file name generation could turn it into more than one thing, and what would that mean? The C shell handles it differently: % set y="BIG trouble" % echo $y >$y $y: Ambiguous. As should be clear by now, assignment to keyword parameters is another context where substitution is done but file name generation is not.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/01/88)
In article <17661@adm.BRL.MIL> wmartin@almsa-1.arpa (Will Martin -- AMXAL-RI) writes: >cat foo > /data/sa*/bar >What I don't understand is why the expansion doesn't work under "sh". It was a deliberate design decision. The target of > should be just one word, not the potential multiple words that wildcard expansion might produce. To avoid unpleasant surprises, "sh" doesn't expand wildcards in such contexts. However, note that you can save typing using the BRL Bourne shell by using the filename completion feature to automatically fill in the rest of a pathname segment once you've typed the unambiguous prefix for it. I actually prefer this approach anyway, since I get to see the full expansion before the command is executed.
guy@auspex.UUCP (Guy Harris) (12/01/88)
>And, if "csh" lets this work as shown, why does it NOT work when >creating the file initially? Because a "starname" must match something that already exists. The starname "foo/*/bar" will match all files named "bar" in any subdirectory of "foo" (except those whose name begins with "."). When creating the file initially, it doesn't exist yet....