zsh-workers
 help / color / mirror / code / Atom feed
* 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: 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

* 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

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).