Discussion:
MakeI(1): what means {} ?
(too old to reply)
James K. Lowden
2008-02-16 21:21:58 UTC
Permalink
The make(1) man page explains (sort of) that "Targets and sources may
contain the shell wildcard values.... The value `{}' need not necessarily
be used to describe existing files."

Eh? Forgive me, but my sh(1) man page doesn't mention {} as a Shell
Pattern, or as anything else for that matter. (The term "wildcard" isn't
used. Nor is "glob", unfortunately.)

I think someone reading the docs should be able to figure things out from
first principles:

1. make's man page should say what {} means, and/or
2. sh's man page should say what {} means.

Unless I'm overlooking something obvious?

I know this works:

$ ls dbstream.{h,h.bak}
dbstream.h dbstream.h.bak

and maybe that's what's meant. But I don't find even that idiom explained
in either place.

I'd offer a patch except, er, I don't know the answers to my questions.

(btw, I was looking for a way to use make to say, "copy any files from
dir1 to dir2 where the source file is more recent." No luck so far.)

--jkl
Christer Jansson
2008-02-17 12:24:12 UTC
Permalink
Post by James K. Lowden
The make(1) man page explains (sort of) that "Targets and sources may
contain the shell wildcard values.... The value `{}' need not necessarily
be used to describe existing files."
Eh? Forgive me, but my sh(1) man page doesn't mention {} as a Shell
Pattern, or as anything else for that matter. (The term "wildcard" isn't
used. Nor is "glob", unfortunately.)
I didn't find anything about it in the NetBSD sh(1) man page, either.
I did however react on that it seems very brief in comparison with
other sh(1) (or ksh(1) if you think it matters) man pages I've seen.

When I type "man sh" on my Mac OS X system, I get the bash(1) man page
(sh may actually start bash in posix-compliant mode which I guess
would be fair enough), and there, there is a heading "Brace expansion"
describing that feature. So *if* brace expansion is in the standard
(haven't read it that closely), *and* Mac OS X bash(1) gets it right,
*and* NetBSD also complies with the standard and gets it right, this
description will suffice:

Brace Expansion
Brace expansion is a mechanism by which arbitrary strings may be gener-
ated. This mechanism is similar to pathname expansion, but the file-
names generated need not exist. Patterns to be brace expanded take the
form of an optional preamble, followed by a series of comma-separated
strings between a pair of braces, followed by an optional postscript.
The preamble is prefixed to each string contained within the braces,
and the postscript is then appended to each resulting string, expanding
left to right.

Brace expansions may be nested. The results of each expanded string
are not sorted; left to right order is preserved. For example,
a{d,c,b}e expands into `ade ace abe'.

Brace expansion is performed before any other expansions, and any char-
acters special to other expansions are preserved in the result. It is
strictly textual. Bash does not apply any syntactic interpretation to
the context of the expansion or the text between the braces.

A correctly-formed brace expansion must contain unquoted opening and
closing braces, and at least one unquoted comma. Any incorrectly
formed brace expansion is left unchanged. A { or , may be quoted with
a backslash to prevent its being considered part of a brace expression.
To avoid conflicts with parameter expansion, the string ${ is not con-
sidered eligible for brace expansion.

This construct is typically used as shorthand when the common prefix of
the strings to be generated is longer than in the above example:

mkdir /usr/local/src/bash/{old,new,dist,bugs}
or
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

Brace expansion introduces a slight incompatibility with historical
versions of sh. sh does not treat opening or closing braces specially
when they appear as part of a word, and preserves them in the output.
Bash removes braces from words as a consequence of brace expansion.
For example, a word entered to sh as file{1,2} appears identically in
the output. The same word is output as file1 file2 after expansion by
bash. If strict compatibility with sh is desired, start bash with the
+B option or disable brace expansion with the +B option to the set com-
mand (see SHELL BUILTIN COMMANDS below).

This is obviously not present on the NetBSD sh(1) man page. Maybe the
guys maintaining it consider it an experimental feature and don't want
to doc it, maybe they just didn't find the time, or maybe they just
missed it.
Post by James K. Lowden
(btw, I was looking for a way to use make to say, "copy any files from
dir1 to dir2 where the source file is more recent." No luck so far.)
I don't remember make rules or syntax very well, not having had to
mess with it for a long time (closing in on a decade, actually!), but
if you specify each source file (in the target directory) as a make
target, and the files in the source directory as dependencies, and a
build command copying the source to the target, that should do the
trick. If you google for make tutorials you ought to find examples
doing just that. (Or even if you try other make(1) pages.)

Hope this helps.
--
Christer
Martin S. Weber
2008-02-17 15:23:11 UTC
Permalink
a) behaviour of {}.

{}, in contrast to the other shell wildcards "need not necessarily
be used to describe existing files.". I.e. the expansion need not
be generated by generating the (string) expansion by only expanding
into existing files. See below what this means.

b) {} doesn't just work :p (old basher, eh?)

/bin/csh: echo a{b,c} -> ab ac
/bin/sh: echo a{b,c} -> a{b,c}
/bin/ksh: set +o braceexpand (default I think); echo a{b,c} -> a{b,c}
/bin/ksh: set -o braceexpand; echo a{b,c} -> ab ac

c) putting things together

mkdir banzai
cd banzai
touch a* ;# creates a file named 'a*'
touch a? ;# touches 'a*'
touch a{1,2} ;# doesn't care about existing files
# but creates two files: a1, a2.
echo a* -> a* a1 a2
echo a? -> a* a1 a2
echo b* b? -> b* b?
touch b{1,2}{a,b}
echo b* b? -> b1a b1b b2a b2b b?

I think the last lines will explain what is meant by "need not necessarily
be used to describe existing files." In contrast to the other shell patterns
you can construct *STRINGS* following a certain rule, and not *MATCH EXISTING
FILES*.

Hope that helps with (the underlying, not your actual) problem.

The {} pattern expansion is documented in ksh(1) and csh(1) btw, both the
shells that support it (in contrast to sh(1)).

Regards,

-Martin
James K. Lowden
2008-02-26 23:26:47 UTC
Permalink
Post by Martin S. Weber
a) behaviour of {}.
{}, in contrast to the other shell wildcards "need not necessarily
be used to describe existing files.". [...]
b) {} doesn't just work :p (old basher, eh?)
/bin/csh: echo a{b,c} -> ab ac
/bin/sh: echo a{b,c} -> a{b,c}
..
Post by Martin S. Weber
The {} pattern expansion is documented in ksh(1) and csh(1) btw, both
the shells that support it (in contrast to sh(1)).
Thanks, Martin, I see. It looks like a failure on the part of the manual
to communicate clearly and completely. When I read the manpage,

"Targets and sources may contain the shell
wildcard values `?', `*', `[]', and `{}'."

I assumed `{}' stood for the literal pair, as in find(1). It's
exceedingly odd that it refers to "shell wildcards" when the shell's own
manpage doesn't use the term or in fact support the described behavior.
FSVO "the shell", of course.

I invoked the following Makefile from both bash and /bin/sh,

t{all}:
echo $@

and got the same results:

$ make -f Makefile
echo tall
tall

Since it doesn't use "the shell" to perform the expansion, it would be
better if it said what it *does* do, maybe by reference to glob(3)?

As someone who arrived on the scene after csh's heyday, I dislike man
pages that say "like csh(1)", or, worse, assume "the shell" is csh(1) of
all things.

Anyone else think this is doc fault?

--jkl

Loading...