Only do brace expansion if they contain a variable or ","

Brace expansion with single words in it is quite useless - `HEAD@{0}`
expanding to `HEAD@0` breaks git.

So we complicate the rule slightly - if there is no variable expansion
or "," inside of braces, they are just treated as literal braces.

Note that this is technically backwards-incompatible, because

    echo foo{0}

will now print `foo{0}` instead of `foo0`. However that's a
technicality because the braces were literally useless in that case.

Our tests needed to be adjusted, but that's because they are meant to
exercise this in weird ways.

I don't believe this will break any code in practice.

Fixes #5869.
This commit is contained in:
Fabian Homborg
2019-05-18 20:31:41 +02:00
parent 15a5c0ed5f
commit 967c1d51ee
8 changed files with 68 additions and 23 deletions

View File

@@ -764,31 +764,41 @@ Examples::
Brace expansion
---------------
A comma separated list of characters enclosed in curly braces will be expanded so each element of the list becomes a new parameter.
A comma separated list of characters enclosed in curly braces will be expanded so each element of the list becomes a new parameter. This is useful to save on typing, and to separate a variable name from surrounding text.
Examples::
echo input.{c,h,txt}
# Outputs 'input.c input.h input.txt'
> echo input.{c,h,txt}
input.c input.h input.txt
mv *.{c,h} src/
> mv *.{c,h} src/
# Moves all files with the suffix '.c' or '.h' to the subdirectory src.
A literal "{}" will not be used as a brace expansion, but if after expansion there is nothing between the braces, the argument will be removed::
> cp file{,.bak}
# Make a copy of `file` at `file.bak`.
echo foo-{}
# Outputs foo-{}
> set -l dogs hot cool cute
> echo {$dogs}dog
hotdog cooldog cutedog
echo foo-{$undefinedvar}
# Output is an empty line - see :ref:`the cartesian product section <cartesian-product>`
If two braces do not contain a "," or a variable expansion, they will not be expanded in this manner::
> echo foo-{}
foo-{}
> git reset --hard HEAD@{2}
# passes "HEAD@{2}" to git
> echo {{a,b}}
{a} {b} # because the inner brace pair is expanded, but the outer isn't.
If there is nothing between a brace and a comma or two commas, it's interpreted as an empty element.
If after expansion there is nothing between the braces, the argument will be removed (see :ref:`the cartesian product section <cartesian-product>`)::
So::
> echo foo-{$undefinedvar}
# Output is an empty line, just like a bare `echo`.
echo {,,/usr}/bin
# Output /bin /bin /usr/bin
If there is nothing between a brace and a comma or two commas, it's interpreted as an empty element::
> echo {,,/usr}/bin
/bin /bin /usr/bin
To use a "," as an element, `quote <#quotes>`_ or `escape <#escapes>`_ it.