Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: On the quoting of braces



On Tue, 06 Dec 2011 23:16:35 +0100
Christian Neukirchen <chneukirchen@xxxxxxxxx> wrote:
> comparing different shells, I noticed zsh is overly careful for unquoted
> braces:
> zsh% echo { foo,bar }
> zsh: parse error near `}'
> 
> Why does this error appear?

zsh allows a "}" to appear other than in command position at the end of
a shell construct or a function definition:

{ echo }

and

fn() { echo }

aren't complete statements in other shells.  So this means a "}" is
treated as special everywhere on the command line.

> The only way to disable it seems to be
> IGNORE_BRACES, which completely disables (the much used) brace expansion.

Yes, this is really a different thing, since it doesn't involve a brace
on its own as an argument.  They shouldn't really be tied together.  In
fact, it looks like this additional effect of IGNORE_BRACES isn't even
documented.

Here's an option IGNORE_CLOSE_BRACES that only disables the first effect.

> ("disable -r '}'" would break "{ cmd; cmd2 }")

More to the point it would break "}" everywere, even in command
position, i.e. "{ cmd; cmd2; }" too.  If you want the shell to treat
close braces as ordinary characters you'll need the semicolon after
"cmd2".

Index: Doc/Zsh/options.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/options.yo,v
retrieving revision 1.103
diff -p -u -r1.103 options.yo
--- Doc/Zsh/options.yo	18 May 2011 01:54:36 -0000	1.103
+++ Doc/Zsh/options.yo	7 Dec 2011 20:28:41 -0000
@@ -548,7 +548,32 @@ cindex(disabling brace expansion)
 cindex(brace expansion, disabling)
 cindex(expansion, brace, disabling)
 item(tt(IGNORE_BRACES) (tt(-I)) <S>)(
-Do not perform brace expansion.
+Do not perform brace expansion.  For historical reasons this
+also includes the effect of the tt(IGNORE_CLOSE_BRACES) option.
+)
+pindex(IGNORE_CLOSE_BRACES)
+pindex(NO_IGNORE_CLOSE_BRACES)
+pindex(IGNORECLOSEBRACES)
+pindex(NOIGNORECLOSEBRACES)
+item(tt(IGNORE_CLOSE_BRACES))(
+When neither this option no tt(IGNORE_BRACES) is set, a sole
+close brace character `tt(})' is syntactically significant at any
+point on a command line.  This has the effect that no semicolon
+or newline is necessarry before the brace terminating a function
+or current shell construct.  When either option is set, a closing brace
+is syntactically significant only in command position.  Unlike
+tt(IGNORE_BRACES), this option does not disable brace expansion.
+
+For example, with both options unset a function may be defined
+in the following fashion:
+
+example(args() { echo $# })
+
+while if either option is set, this does not work and something
+equivalent to the following is required:
+
+example(args() { echo $#; })
+
 )
 pindex(KSH_GLOB)
 pindex(NO_KSH_GLOB)
Index: Src/lex.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/lex.c,v
retrieving revision 1.69
diff -p -u -r1.69 lex.c
--- Src/lex.c	3 Dec 2011 17:24:46 -0000	1.69
+++ Src/lex.c	7 Dec 2011 20:28:41 -0000
@@ -1857,7 +1857,8 @@ exalias(void)
 
 	    /* Then check for a reserved word */
 	    if ((incmdpos ||
-		 (unset(IGNOREBRACES) && zshlextext[0] == '}' && !zshlextext[1])) &&
+		 (unset(IGNOREBRACES) && unset(IGNORECLOSEBRACES) &&
+		  zshlextext[0] == '}' && !zshlextext[1])) &&
 		(rw = (Reswd) reswdtab->getnode(reswdtab, zshlextext))) {
 		tok = rw->token;
 		if (tok == DINBRACK)
Index: Src/options.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/options.c,v
retrieving revision 1.57
diff -p -u -r1.57 options.c
--- Src/options.c	22 Nov 2010 11:42:47 -0000	1.57
+++ Src/options.c	7 Dec 2011 20:28:41 -0000
@@ -159,6 +159,7 @@ static struct optname optns[] = {
 {{NULL, "histverify",	      0},			 HISTVERIFY},
 {{NULL, "hup",		      OPT_EMULATE|OPT_ZSH},	 HUP},
 {{NULL, "ignorebraces",	      OPT_EMULATE|OPT_SH},	 IGNOREBRACES},
+{{NULL, "ignoreclosebraces",  0},			 IGNORECLOSEBRACES},
 {{NULL, "ignoreeof",	      0},			 IGNOREEOF},
 {{NULL, "incappendhistory",   0},			 INCAPPENDHISTORY},
 {{NULL, "interactive",	      OPT_SPECIAL},		 INTERACTIVE},
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.177
diff -p -u -r1.177 zsh.h
--- Src/zsh.h	14 Aug 2011 18:34:28 -0000	1.177
+++ Src/zsh.h	7 Dec 2011 20:28:41 -0000
@@ -2005,6 +2005,7 @@ enum {
     HISTVERIFY,
     HUP,
     IGNOREBRACES,
+    IGNORECLOSEBRACES,
     IGNOREEOF,
     INCAPPENDHISTORY,
     INTERACTIVE,
Index: Test/E01options.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/E01options.ztst,v
retrieving revision 1.25
diff -p -u -r1.25 E01options.ztst
--- Test/E01options.ztst	1 Jul 2011 15:23:03 -0000	1.25
+++ Test/E01options.ztst	7 Dec 2011 20:28:41 -0000
@@ -256,6 +256,8 @@
 ?next one should fail
 ?(eval):1: parse error near `end'
 
+# ` emacs deconfusion
+
   setopt cshjunkiequotes
   print this should cause an error >&2
   eval "print 'line one
@@ -271,6 +273,8 @@
 ?(eval):1: unmatched '
 ?this should not
 
+# ' emacs deconfusion
+
   nullcmd() { print '$NULLCMD run'; }
   readnullcmd() { print 'Running $READNULLCMD'; cat; }
   NULLCMD=nullcmd
@@ -901,6 +905,8 @@
 ?(eval):exec:6: ls: restricted
 ?(eval):unsetopt:7: can't change option: restricted
 
+# ' emacs deconfusion
+
   fn() {
     print =ls ={ls,}
     local foo='=ls'
@@ -1081,3 +1087,12 @@
 ?+(eval):4> fn
 ?+fn:0> print message
 ?+(eval):5> unsetopt xtrace
+
+  setopt ignoreclosebraces
+  eval "icb_test() { echo this is OK; }"
+  icb_test
+  icb_args() { print $#; }
+  eval "icb_args { this, is, ok, too }"
+0:IGNORE_CLOSE_BRACES option
+>this is OK
+>6


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author