LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   bash question on nested braces (https://www.linuxquestions.org/questions/linux-newbie-8/bash-question-on-nested-braces-4175464675/)

CelticFiddler 06-04-2013 09:12 AM

bash question on nested braces
 
I was reading through the latest edition of Linux Programming Unleased. On page 717, the author gives an example:
Code:

$ echo c{ar,at,an}s
which results in: cars cats cans

That works on my Ubuntu system (bash 4.2.25(1)-release) exactly as the example states.

However, the author then says that since braces can be nested, the command:
Code:

$ echo c{a{r,t,n}}s
should produce the same output. But on my system, the output is:

c{ar}s c{at}s c{an}s

Is this a bash bug?

I get the expected output for the following command:
Code:

echo c{a{r,t},an}s
and also:
Code:

echo c{a{r,t,},a{b,n}}
so is output for the case c{a{r,t,n}}s a bug, or a subtle exception?

grail 06-04-2013 09:43 AM

You probably have to wait for David.H to look at this, but I believe it is a subtle exception. The exception being that without a comma separated list the braces are interpreted literally.

I found this by doing the following:
Code:

$ echo c{a{r,t,n},}s
cars cats cans cs

So as the man page says, {} is used to denote a list, so with the absence of a list I would guess it reverts to literal braces:
Code:

{ list; }
              list is simply executed in the current shell environment.  list must be terminated with a newline or semicolon.  This is known as a group command.  The return status is the exit status of list.  Note that  unlike  the
              metacharacters  (  and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized.  Since they do not cause a word break, they must be separated from list by whitespace or another
              shell metacharacter.


Beryllos 06-04-2013 10:04 AM

There must be at least one comma or sequence expression.

Quote:

A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression. Any incorrectly formed brace expansion is left unchanged.
That is from http://www.gnu.org/software/bash/man...Expansion.html
I added the bold highlighting.

So you see that without a comma in your example, it is considered an "incorrectly formed brace expansion" and is "left unchanged."

David the H. 06-04-2013 02:27 PM

Perhaps the code above does work in some other shell like zsh?

But I think Beryllos has found the key to it in bash. A brace expansion can only be used inside another if it's completely contained inside a list sub-entry. It looks like your book is wrong.

It appears that bash is reading it with the following three parts, with only the middle part being a valid brace expansion:
Code:

c{a        #beginning string
{r,t,n}    #brace expansion
}s        #ending string

The last two expansions work because they break down this way:

Code:

echo c{a{r,t},an}s
c        #beginning string
{        #main brace expansion start
a{r,t}  #first element (nested expansion)
,        #list separator
an      #second element
}        #main brace expansion end
s        #ending string

echo c{a{r,t,},a{b,n}}
c        #beginning string
{        #main brace expansion start
a{r,t,}  #first element (nested expansion)
,        #list separator
a{b,n}  #second element (nested expansion)
}        #main brace expansion end

Nested expansions can be quite a headache. ;)

I've found the bash-hacker's page on it to be quite useful.
http://wiki.bash-hackers.org/syntax/expansion/brace

Madhu Desai 06-04-2013 02:56 PM

This is what i got. it wont work in bash shell...

Code:

$ echo $0
/bin/bash

$ echo c{a{r,t,n}}s
c{ar}s c{at}s c{an}s

$ /bin/sh
sh-4.1$ echo c{a{r,t,n}}s
c{ar}s c{at}s c{an}s

sh-4.1$ /bin/dash
$ echo c{a{r,t,n}}s
c{a{r,t,n}}s

$ /bin/tcsh
$ echo c{a{r,t,n}}s
cars cats cans

$ /bin/csh
$ echo c{a{r,t,n}}s
cars cats cans


David the H. 06-04-2013 03:24 PM

Brace expansion is only available in some advanced shells like bash, ksh, and probably zsh. It won't work in strictly posix-based shells like dash.

/bin/sh is your system's posix-supporting shell, which is usually a symlink to another interpreter like bash or dash. So it may work or it may not, depending on what that link is.

And we've already explained the problems with the above line in bash (it does work, it just doesn't work as expected by the OP).

But it is interesting to see that it apparently also works in c-shell environments, and apparently works as expected.

Kenhelm 06-05-2013 10:23 AM

The book is correct for old versions of bash.
Bash started to behave differently somewhere around the introduction of version 4.
Code:

echo c{a{r,t,n}}s

cars cats cans          # bash 2.05b.0(1)
cars cats cans          # bash 3.1.17(2)
c{ar}s c{at}s c{an}s    # bash 4.1.5(2)
c{ar}s c{at}s c{an}s    # bash 4.2.37(2)


David the H. 06-06-2013 12:54 PM

Even more interesting stuff to learn! I guess bash originally tried to emulate the csh style, but later went its own way for some reason.

Incidentally, I made an error in my last post. Posix does have the "{a,b,c}" list style of expansion, but it does not support the "{a..z}" range style.

CelticFiddler 06-29-2022 09:16 AM

Works in bash 4.3.48
 
I revisited this today, and tried
Code:

echo c{a{r,t,n}}s
and got the output
Code:

cars cats cans
...so it appears that this is version-dependent.

grail 06-30-2022 04:57 AM

Still the same for version 5.1.16
Code:

30-06-2022 17:56:07][~]
[grail@killrazor]$ echo c{a{r,t,n}}s
c{ar}s c{at}s c{an}s


pan64 06-30-2022 06:40 AM

Quote:

Originally Posted by CelticFiddler (Post 6364384)
I revisited this today, and tried
Code:

echo c{a{r,t,n}}s
and got the output
Code:

cars cats cans
...so it appears that this is version-dependent.

Code:

$ echo c{a{r,t,n}}s
c{ar}s c{at}s c{an}s
$ bash --version
GNU bash, version 4.3.48(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.


boughtonp 06-30-2022 07:32 AM


 
To reiterate what was stated in post #3 from June 2013 this behaviour is clearly described in the Brace Expansion documentation:

Quote:

Originally Posted by https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html
Brace expansions may be nested.
...
A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression. Any incorrectly formed brace expansion is left unchanged.

Without a comma, and without a sequence expression {INTEGER..INTEGER}, the outer expansion is incorrectly formed and thus should be left unchanged.

If someone feels they have found a bug in a supported version of Bash, they should report it to GNU on the Bash bug mailing list, though I'm not sure 4.3 is supported.



All times are GMT -5. The time now is 03:40 AM.