* f() { ...; } > file @ 2008-11-05 21:20 Stephane Chazelas 2008-11-05 22:49 ` Phil Pennock ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Stephane Chazelas @ 2008-11-05 21:20 UTC (permalink / raw) To: Zsh hackers list Hiya, $ bash -c 'foo() { echo a >&3; } 3>&1; foo' a $ ksh -c 'foo() { echo a >&3; } 3>&1; foo' a $ zsh -c 'foo() { echo a >&3; } 3>&1; foo' foo: 3: bad file descriptor $ ARGV0=sh zsh -c 'foo() { command echo a >&3; } 3>&1; foo' foo: 3: bad file descriptor It looks like zsh evaluates the redirection at the time the function is defined rather than when it is called. It's OK when declaring the function as foo() echo a > file or foo() (echo a) > file instead of foo() { echo a; } > file -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: f() { ...; } > file 2008-11-05 21:20 f() { ...; } > file Stephane Chazelas @ 2008-11-05 22:49 ` Phil Pennock 2008-11-06 14:38 ` Stephane Chazelas 2008-11-13 14:25 ` Stephane Chazelas 2008-11-13 14:42 ` [PATCH] " Stephane Chazelas 2 siblings, 1 reply; 10+ messages in thread From: Phil Pennock @ 2008-11-05 22:49 UTC (permalink / raw) To: Zsh hackers list On 2008-11-05 at 21:20 +0000, Stephane Chazelas wrote: > $ bash -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ ksh -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ zsh -c 'foo() { echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > $ ARGV0=sh zsh -c 'foo() { command echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > > It looks like zsh evaluates the redirection at the time the > function is defined rather than when it is called. Back to front. I think that you're misunderstanding what bash et al are doing. They're not deferring the redirection, they're resolving the redirection at definition time so that it remains bound to stdout. % bash -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo' % bash -c 'foo() { echo a >&3; } 3>&1; foo' a % ksh -c 'foo() { echo a >&3; } 3>&1; foo' a % ksh -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo' % ksh -c 'echo $KSH_VERSION' @(#)PD KSH v5.2.14.2 99/07/13.2 % ksh93 -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo' % ksh93 -c 'foo() { echo a >&3; } 3>&1; foo' a % ksh93 -c 'echo $KSH_VERSION' Version M 93t 2008-07-25 Whereas zsh defers evaluating the file-descriptor: % zsh -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo 3>&2' a % (There might be a mistake in my analysis; collapsing into head-cold, mind fuzzy, not diagnosing the shell problem further). ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: f() { ...; } > file 2008-11-05 22:49 ` Phil Pennock @ 2008-11-06 14:38 ` Stephane Chazelas 0 siblings, 0 replies; 10+ messages in thread From: Stephane Chazelas @ 2008-11-06 14:38 UTC (permalink / raw) To: Zsh hackers list On Wed, Nov 05, 2008 at 02:49:24PM -0800, Phil Pennock wrote: > On 2008-11-05 at 21:20 +0000, Stephane Chazelas wrote: > > $ bash -c 'foo() { echo a >&3; } 3>&1; foo' > > a > > $ ksh -c 'foo() { echo a >&3; } 3>&1; foo' > > a > > $ zsh -c 'foo() { echo a >&3; } 3>&1; foo' > > foo: 3: bad file descriptor > > $ ARGV0=sh zsh -c 'foo() { command echo a >&3; } 3>&1; foo' > > foo: 3: bad file descriptor > > > > It looks like zsh evaluates the redirection at the time the > > function is defined rather than when it is called. > > Back to front. > > I think that you're misunderstanding what bash et al are doing. They're > not deferring the redirection, they're resolving the redirection at > definition time so that it remains bound to stdout. hi Phil, no, there're not. If that were true (and if I understand correctly what you're saying), bash -c 'f() { :; } 3>&1; echo foo >&3' would output foo on stdout. defining a function foo is sticking foo() in front of a statement. That has been like that since functions have been implemented in the Bourne shell. So foo() echo bar > baz is defining a function foo that does "echo bar > baz". All the shells are doing that, except zsh and only if the statement is of the form { ...; } <redirections> (there might be other cases). > > % bash -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo' Yes. It's as if you had run: bash -c 'exec >/dev/null; { echo a >&3; } 3>&1' My understanding is that for some reason, % zsh -c 'foo() { echo a >&3; } 3>&1; exec >/dev/null; foo' Is as if you had run: % zsh -c '3>&1; exec >/dev/null; { echo a >&3; }' -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: f() { ...; } > file 2008-11-05 21:20 f() { ...; } > file Stephane Chazelas 2008-11-05 22:49 ` Phil Pennock @ 2008-11-13 14:25 ` Stephane Chazelas 2008-11-13 14:42 ` [PATCH] " Stephane Chazelas 2 siblings, 0 replies; 10+ messages in thread From: Stephane Chazelas @ 2008-11-13 14:25 UTC (permalink / raw) To: Zsh hackers list On Wed, Nov 05, 2008 at 09:20:36PM +0000, Stephane Chazelas wrote: [...] > $ bash -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ ksh -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ zsh -c 'foo() { echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > $ ARGV0=sh zsh -c 'foo() { command echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > > It looks like zsh evaluates the redirection at the time the > function is defined rather than when it is called. > > It's OK when declaring the function as > > foo() echo a > file > or > foo() (echo a) > file > > instead of > > foo() { echo a; } > file [...] Interestingly, foo() > file { echo a; } works: ~$ bash -c 'f() { echo a; } > /dev/null; declare -f' f () { echo a } > /dev/null ~$ ksh -c 'f() { echo a; } > /dev/null; typeset -f' f() { echo a; } > /dev/null;% ~$ zsh -c 'f() { echo a; } > /dev/null; typeset -f' f () { echo a } ~$ zsh -c 'f() > /dev/null { echo a; }; typeset -f' f () { { echo a } > /dev/null } -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH] Re: f() { ...; } > file 2008-11-05 21:20 f() { ...; } > file Stephane Chazelas 2008-11-05 22:49 ` Phil Pennock 2008-11-13 14:25 ` Stephane Chazelas @ 2008-11-13 14:42 ` Stephane Chazelas 2008-11-13 14:52 ` Peter Stephenson 2008-11-13 14:55 ` Stephane Chazelas 2 siblings, 2 replies; 10+ messages in thread From: Stephane Chazelas @ 2008-11-13 14:42 UTC (permalink / raw) To: Zsh hackers list On Wed, Nov 05, 2008 at 09:20:36PM +0000, Stephane Chazelas wrote: [...] > $ bash -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ ksh -c 'foo() { echo a >&3; } 3>&1; foo' > a > $ zsh -c 'foo() { echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > $ ARGV0=sh zsh -c 'foo() { command echo a >&3; } 3>&1; foo' > foo: 3: bad file descriptor > > It looks like zsh evaluates the redirection at the time the > function is defined rather than when it is called. > > It's OK when declaring the function as > > foo() echo a > file > or > foo() (echo a) > file > > instead of > > foo() { echo a; } > file [...] The patch below seems to fix it. It just removes the special case of f() { }. I don't why it was there in the first place. rev 1.1 of parse.c already had it. Not sure how many things this patch would break ;) Index: Src/parse.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/parse.c,v retrieving revision 1.76 diff -p -u -r1.76 parse.c --- Src/parse.c 29 Sep 2008 08:46:33 -0000 1.76 +++ Src/parse.c 13 Nov 2008 14:31:10 -0000 @@ -1685,34 +1685,20 @@ par_simple(int *complex, int nr) onp = ecnpats; ecnpats = 0; - if (tok == INBRACE) { - int c = 0; + int ll, sl, pl, c = 0; - yylex(); - par_list(&c); - if (tok != OUTBRACE) { - cmdpop(); - lineno += oldlineno; - ecnpats = onp; - ecssub = oecssub; - YYERROR(oecused); - } - yylex(); - } else { - int ll, sl, pl, c = 0; - - ll = ecadd(0); - sl = ecadd(0); - pl = ecadd(WCB_PIPE(WC_PIPE_END, 0)); - - if (!par_cmd(&c)) { - cmdpop(); - YYERROR(oecused); - } - - set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); - set_list_code(ll, (Z_SYNC | Z_END), c); + ll = ecadd(0); + sl = ecadd(0); + pl = ecadd(WCB_PIPE(WC_PIPE_END, 0)); + + if (!par_cmd(&c)) { + cmdpop(); + YYERROR(oecused); } + + set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); + set_list_code(ll, (Z_SYNC | Z_END), c); + cmdpop(); ecadd(WCB_END()); -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Re: f() { ...; } > file 2008-11-13 14:42 ` [PATCH] " Stephane Chazelas @ 2008-11-13 14:52 ` Peter Stephenson 2008-11-13 15:03 ` Stephane Chazelas 2008-11-13 14:55 ` Stephane Chazelas 1 sibling, 1 reply; 10+ messages in thread From: Peter Stephenson @ 2008-11-13 14:52 UTC (permalink / raw) To: Zsh hackers list Stephane Chazelas wrote: > The patch below seems to fix it. It just removes the special > case of f() { }. I don't why it was there in the first place. > rev 1.1 of parse.c already had it. That's because you've made all functions with braces parse as if they contain current shell structures; you'll see they're output with an unnecessary extra set of "{"s. This works because it just makes the code behave like the non-confusing way to do it, with the redirection inside the function. -- Peter Stephenson <pws@csr.com> Software Engineer CSR PLC, Churchill House, Cambridge Business Park, Cowley Road Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Re: f() { ...; } > file 2008-11-13 14:52 ` Peter Stephenson @ 2008-11-13 15:03 ` Stephane Chazelas 2008-11-13 15:13 ` Stephane Chazelas 0 siblings, 1 reply; 10+ messages in thread From: Stephane Chazelas @ 2008-11-13 15:03 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh hackers list On Thu, Nov 13, 2008 at 02:52:59PM +0000, Peter Stephenson wrote: > Stephane Chazelas wrote: > > The patch below seems to fix it. It just removes the special > > case of f() { }. I don't why it was there in the first place. > > rev 1.1 of parse.c already had it. > > That's because you've made all functions with braces parse as if they > contain current shell structures; you'll see they're output with an > unnecessary extra set of "{"s. This works because it just makes the > code behave like the non-confusing way to do it, with the redirection > inside the function. [...] Well, it depends how you regard the function syntax. In the Bourne shell and its derivatives, defining a function is really sticking foo() in front of a command. The "{" and "}" are not part of the syntax of a function definition. Note that POSIX has specified it with a restriction in that you can only stick "foo()" in front of complex command, and bash is the only shell to enforce that restriction. bash allows: foo() for i do echo "$i"; done but not foo() echo "$*" contrary to all the other Bourne like shells which allow both. Now, I agree that $ /tmp/Z/bin/zsh -c 'f() { :; }; typeset -f' f () { { : } } is not ideal ;). Looks like the fix is not as easy as that. -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Re: f() { ...; } > file 2008-11-13 15:03 ` Stephane Chazelas @ 2008-11-13 15:13 ` Stephane Chazelas 2008-11-13 15:27 ` Peter Stephenson 0 siblings, 1 reply; 10+ messages in thread From: Stephane Chazelas @ 2008-11-13 15:13 UTC (permalink / raw) To: Peter Stephenson, Zsh hackers list On Thu, Nov 13, 2008 at 03:03:35PM +0000, Stephane Chazelas wrote: [...] > Note that POSIX has specified it with a restriction in that you > can only stick "foo()" in front of complex command, and bash is > the only shell to enforce that restriction. [...] Sorry the proper term is "compound command". Here is the text from SUSv3: SUS> The format of a function definition command is as SUS> follows: SUS> SUS> fname() compound-command[io-redirect ...] SUS> [...] SUS> The argument compound-command represents a compound SUS> command, as described in Compound Commands. SUS> SUS> When the function is declared, none of the expansions in SUS> Word Expansions shall be performed on the text in SUS> compound-command or io-redirect; all expansions shall be SUS> performed as normal each time the function is called. SUS> Similarly, the optional io-redirect redirections and any SUS> variable assignments within compound-command shall be SUS> performed during the execution of the function itself, SUS> not the function definition. See Consequences of Shell SUS> Errors for the consequences of failures of these SUS> operations on interactive and non-interactive shells. [...] SUS> The compound-command shall be executed whenever the SUS> function name is specified as the name of a simple SUS> command (see Command Search and Execution). The operands SUS> to the command temporarily shall become the positional SUS> parameters during the execution of the compound-command; SUS> the special parameter '#' also shall be changed to SUS> reflect the number of operands. The special parameter 0 SUS> shall be unchanged. When the function completes, the SUS> values of the positional parameters and the special SUS> parameter '#' shall be restored to the values they had SUS> before the function was executed. If the special built-in SUS> return is executed in the compound-command, the function SUS> completes and execution shall resume with the next SUS> command after the function call. So, at the moment, zsh is not conformant. The patch I suggested seems to fix it but introduces some display glitches. -- Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] Re: f() { ...; } > file 2008-11-13 15:13 ` Stephane Chazelas @ 2008-11-13 15:27 ` Peter Stephenson 0 siblings, 0 replies; 10+ messages in thread From: Peter Stephenson @ 2008-11-13 15:27 UTC (permalink / raw) To: Zsh hackers list Stephane Chazelas wrote: > So, at the moment, zsh is not conformant. The patch I suggested > seems to fix it but introduces some display glitches. It's not just in the display, there's a whole extra layer of evaluation compared with the standard you gave. A function in zsh is a separate entity, not a name for another structure. The zsh-style autoloads wouldn't work otherwise. -- Peter Stephenson <pws@csr.com> Software Engineer CSR PLC, Churchill House, Cambridge Business Park, Cowley Road Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: f() { ...; } > file 2008-11-13 14:42 ` [PATCH] " Stephane Chazelas 2008-11-13 14:52 ` Peter Stephenson @ 2008-11-13 14:55 ` Stephane Chazelas 1 sibling, 0 replies; 10+ messages in thread From: Stephane Chazelas @ 2008-11-13 14:55 UTC (permalink / raw) To: Zsh hackers list On Thu, Nov 13, 2008 at 02:42:12PM +0000, Stephane Chazelas wrote: [...] > The patch below seems to fix it. It just removes the special > case of f() { }. I don't why it was there in the first place. > rev 1.1 of parse.c already had it. [...] I had a look at the old releases. It looks like in the beginning only the: f() { ... } syntax was supported (I'm not talking of the function foo {...} ksh syntax here). Then, as part of the "short loops" feature (disabled with setopt noshortloops), support for: f() any command was added (but disabled upon setopt noshortloops). Then later the check for noshortloops was removed, possibly by someone who realised that "emulate sh" would set noshortloops and therefore break compatibility with sh which allows f() cmd Cheers, Stéphane ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-11-13 15:28 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-11-05 21:20 f() { ...; } > file Stephane Chazelas 2008-11-05 22:49 ` Phil Pennock 2008-11-06 14:38 ` Stephane Chazelas 2008-11-13 14:25 ` Stephane Chazelas 2008-11-13 14:42 ` [PATCH] " Stephane Chazelas 2008-11-13 14:52 ` Peter Stephenson 2008-11-13 15:03 ` Stephane Chazelas 2008-11-13 15:13 ` Stephane Chazelas 2008-11-13 15:27 ` Peter Stephenson 2008-11-13 14:55 ` Stephane Chazelas
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).