zsh-workers
 help / color / mirror / code / Atom feed
* Request: a way to get the subshell level nesting
@ 2008-09-05 14:11 Rocky Bernstein
  2008-09-05 19:49 ` Phil Pennock
  2008-09-05 20:45 ` Peter Stephenson
  0 siblings, 2 replies; 6+ messages in thread
From: Rocky Bernstein @ 2008-09-05 14:11 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 962 bytes --]

It would be great if there were a way to get the subshell level nesting. ksh
uses .sh.level and bash BASH_SUBSHELL.

A debugger uses this in two ways. First to indicate the level of subshell
nesting on prompts, so that as you are following along you won't be
surprised when a variable which had a value get unset or the value restored
to its previous value. And second to maintain global state.

The general pattern here is

   debug_hook:
        if ((subshell_level < old_subshell_level)) ; then
            eval journal file
        fi
       save old subshell level
       work, work,
       ...
       something that should set or change global state:
           save global variable and value in journal file,
           e.g.  cmd='x=5'; eval $cmd; echo "$cmd" >> journal_file


It also occurs to me that if there were a variable that automatically got
*unset* and stayed that way
until explicitly set, then that could be used to sumulate such a variable.

[-- Attachment #2: Type: text/html, Size: 1515 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Request: a way to get the subshell level nesting
  2008-09-05 14:11 Request: a way to get the subshell level nesting Rocky Bernstein
@ 2008-09-05 19:49 ` Phil Pennock
  2008-09-05 19:55   ` Rocky Bernstein
  2008-09-05 20:45 ` Peter Stephenson
  1 sibling, 1 reply; 6+ messages in thread
From: Phil Pennock @ 2008-09-05 19:49 UTC (permalink / raw)
  To: Rocky Bernstein; +Cc: Zsh hackers list

On 2008-09-05 at 10:11 -0400, Rocky Bernstein wrote:
> It would be great if there were a way to get the subshell level nesting. ksh
> uses .sh.level and bash BASH_SUBSHELL.

I don't think zsh has that directly as a variable, but it does have %_
for prompt substitution, producing on stdout a list of words identifying
the nested parser states.  It's output text, not a data structure
internal to the shell (so not an array).

zsh% for i in 1; do if [[ x == x ]]; then print -P %_ ; fi; done 
for then
zsh%

Of course, capturing that in $(...) will add a cmdsubst to the end.

-Phil


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Request: a way to get the subshell level nesting
  2008-09-05 19:49 ` Phil Pennock
@ 2008-09-05 19:55   ` Rocky Bernstein
  0 siblings, 0 replies; 6+ messages in thread
From: Rocky Bernstein @ 2008-09-05 19:55 UTC (permalink / raw)
  To: Rocky Bernstein, Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1243 bytes --]

Thanks for the information. Alas, I don't believe this is does what is
needed.

Here is output from no subshell nesting, one subshell, and then two:

$ for i in 1; do if [[ x == x ]]; then print -P %_ ; fi; done
for then
$ (for i in 1; do if [[ x == x ]]; then print -P %_ ; fi; done)
for then
$ ( (for i in 1; do if [[ x == x ]]; then print -P %_ ; fi; done) )
for then

In all cases I get the same output with no indication in the last two cases
that they are inside one or two subshells.



On Fri, Sep 5, 2008 at 3:49 PM, Phil Pennock <
zsh-workers+phil.pennock@spodhuis.org<zsh-workers%2Bphil.pennock@spodhuis.org>
> wrote:

> On 2008-09-05 at 10:11 -0400, Rocky Bernstein wrote:
> > It would be great if there were a way to get the subshell level nesting.
> ksh
> > uses .sh.level and bash BASH_SUBSHELL.
>
> I don't think zsh has that directly as a variable, but it does have %_
> for prompt substitution, producing on stdout a list of words identifying
> the nested parser states.  It's output text, not a data structure
> internal to the shell (so not an array).
>
> zsh% for i in 1; do if [[ x == x ]]; then print -P %_ ; fi; done
> for then
> zsh%
>
> Of course, capturing that in $(...) will add a cmdsubst to the end.
>
> -Phil
>

[-- Attachment #2: Type: text/html, Size: 1658 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Request: a way to get the subshell level nesting
  2008-09-05 14:11 Request: a way to get the subshell level nesting Rocky Bernstein
  2008-09-05 19:49 ` Phil Pennock
@ 2008-09-05 20:45 ` Peter Stephenson
  2008-09-05 21:36   ` Rocky Bernstein
  1 sibling, 1 reply; 6+ messages in thread
From: Peter Stephenson @ 2008-09-05 20:45 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 5 Sep 2008 10:11:45 -0400"Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> It would be great if there were a way to get the subshell level nesting. ksh
> uses .sh.level and bash BASH_SUBSHELL.

This is easy; the only decision is whether the value should reflect a
logical or an actual subshell.  I think the former, since the only
difference is to optimise out an exec when the shell is going to exit
anyway, and I think from the user's point of view that should be treated
identically to a real exec.

To explain:  in, for example,

  ( (print $ZSH_SUBSHELL) )

the shell forks, looks at what it's got to do, realises it's the last
command to execute in the current subshell, and so doesn't bother to
fork again.  If the first subshell were not about to exit it would fork,
so in

  ( (print $ZSH_SUBSHELL); print $ZSH_SUBSHELL )

it does fork again for the inner subshell.

I've made these print "2", and "2" and "1", respectively, which is what
you'd naively expect.

Also,

  eval 'print $ZSH_SUBSHELL' &

prints 1.  It's explicitly forked from the main shell, so I think that's
reasonable.  Bash works this way, too.

Index: Doc/Zsh/params.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/params.yo,v
retrieving revision 1.48
diff -u -r1.48 params.yo
--- Doc/Zsh/params.yo	31 Jul 2008 13:53:28 -0000	1.48
+++ Doc/Zsh/params.yo	5 Sep 2008 20:40:41 -0000
@@ -731,6 +731,13 @@
 See ifzman(the section `The zsh/sched Module' in zmanref(zshmodules))\
 ifnzman(noderef(The zsh/sched Module)).
 )
+vindex(ZSH_SUBSHELL <S>)
+item(tt(ZSH_SUBSHELL))(
+Readonly integer.  Initially zero, incremented each time the shell forks
+to create a subshell for executing code.  Hence `tt((print $ZSH_SUBSHELL))'
+and `tt(print $(print $ZSH_SUBSHELL))' output 1, while
+`tt(( (print $ZSH_SUBSHELL) ))' outputs 2.
+)
 vindex(ZSH_VERSION)
 item(tt(ZSH_VERSION))(
 The version number of this zsh.
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.147
diff -u -r1.147 exec.c
--- Src/exec.c	5 Sep 2008 09:05:23 -0000	1.147
+++ Src/exec.c	5 Sep 2008 20:40:43 -0000
@@ -910,6 +910,13 @@
     }
     if (!(flags & ESUB_FAKE))
 	subsh = 1;
+    /*
+     * Increment the visible parameter ZSH_SUBSHELL even if this
+     * is a fake subshell because we are exec'ing at the end.
+     * Logically this should be equivalent to a real subshell so
+     * we don't hang out the dirty washing.
+     */
+    zsh_subshell++;
     if ((flags & ESUB_REVERTPGRP) && getpid() == mypgrp)
 	release_pgrp();
     if (SHTTY != -1) {
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.144
diff -u -r1.144 params.c
--- Src/params.c	31 Jul 2008 13:53:28 -0000	1.144
+++ Src/params.c	5 Sep 2008 20:40:44 -0000
@@ -85,7 +85,8 @@
      lastpid,		/* $!           */
      columns,		/* $COLUMNS     */
      lines,		/* $LINES       */
-     ppid;		/* $PPID        */
+     ppid,		/* $PPID        */
+     zsh_subshell;	/* $ZSH_SUBSHELL */
 /**/
 zlong lineno,		/* $LINENO      */
      zoptind,		/* $OPTIND      */
@@ -291,6 +292,7 @@
 IPDEF4("HISTCMD", &curhist),
 IPDEF4("LINENO", &lineno),
 IPDEF4("PPID", &ppid),
+IPDEF4("ZSH_SUBSHELL", &zsh_subshell),
 
 #define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0}
 IPDEF5("COLUMNS", &columns, zlevar_gsu),
Index: Test/D04parameter.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/D04parameter.ztst,v
retrieving revision 1.33
diff -u -r1.33 D04parameter.ztst
--- Test/D04parameter.ztst	25 Mar 2008 17:47:11 -0000	1.33
+++ Test/D04parameter.ztst	5 Sep 2008 20:40:44 -0000
@@ -1047,3 +1047,18 @@
 >and !that!
 >of *this*
 >or (the|other)
+
+  print $ZSH_SUBSHELL
+  (print $ZSH_SUBSHELL)
+  ( (print $ZSH_SUBSHELL) )
+  ( (print $ZSH_SUBSHELL); print $ZSH_SUBSHELL )
+  print $(print $ZSH_SUBSHELL)
+  cat =(print $ZSH_SUBSHELL)
+0:ZSH_SUBSHELL
+>0
+>1
+>2
+>2
+>1
+>1
+>1


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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Request: a way to get the subshell level nesting
  2008-09-05 20:45 ` Peter Stephenson
@ 2008-09-05 21:36   ` Rocky Bernstein
  2008-09-06 21:23     ` Peter Stephenson
  0 siblings, 1 reply; 6+ messages in thread
From: Rocky Bernstein @ 2008-09-05 21:36 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 2599 bytes --]

Again, many thanks. I'll probably start putting this in prompt information
over the weekend. And again, alas it removes my excuse to blame zsh for why
my code is so broken in this regard ;-)

Comments in line.

On Fri, Sep 5, 2008 at 4:45 PM, Peter Stephenson <
p.w.stephenson@ntlworld.com> wrote:

> On Fri, 5 Sep 2008 10:11:45 -0400"Rocky Bernstein" <
> rocky.bernstein@gmail.com> wrote:
> > It would be great if there were a way to get the subshell level nesting.
> ksh
> > uses .sh.level and bash BASH_SUBSHELL.
>
> This is easy;


(Thought it would; but it's good to get that confirmed.)


> the only decision is whether the value should reflect a
> logical or an actual subshell.  I think the former, since the only
> difference is to optimise out an exec when the shell is going to exit
> anyway, and I think from the user's point of view that should be treated
> identically to a real exec.


I described my motivation. First as status information, second to let folks
realize that values may have gotten discarded and third to make facilitate
picking up state information to be passed back (without doing unnecessary
work in the majority of the cases where there is no subshell change.)

I think some in some of the optimization cases it doesn't matter all that
much, so I leave it to your judgment.

However, I find it interesting because I had a discussion about something
very similar with David Korn regarding SHLVL which should be added soon to
ksh. He had the same question because in some cases he optimizes a recursive
shell out if the say the shell call is in fact the last line of the script.
What was done there was to set SHLVL to be exactly what goes on, not trying
to hide the optimization done.

And in that case there is a reason why this is desirable. In a program such
as bashdb when a "quit" is done we may really need to quit several levels of
shells that may have gotten invoked in between.
Suppose you were writing a debugger for GNU Make. You'd have the same issue.
Or any program
that might call itself recursively and you don't have control in between of
how many *other* recursive shell invocations might have gone on.

So here we need the actual number counting whatever optimization was done,
not the virtual number of shells.  And here I don't think it too bad to have
the user aware that an optimization was done. When one debugs optimized C
code in gcc there are corresponding issues that any competent programmer
just needs to be aware of. Like in-lined functions or statements which
appear out of order because that's the way assembly code was reorganized.

[-- Attachment #2: Type: text/html, Size: 3343 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Request: a way to get the subshell level nesting
  2008-09-05 21:36   ` Rocky Bernstein
@ 2008-09-06 21:23     ` Peter Stephenson
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Stephenson @ 2008-09-06 21:23 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 5 Sep 2008 17:36:37 -0400
"Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> In a program such
> as bashdb when a "quit" is done we may really need to quit several levels of
> shells that may have gotten invoked in between.
> Suppose you were writing a debugger for GNU Make. You'd have the same issue.
> Or any program
> that might call itself recursively and you don't have control in between of
> how many *other* recursive shell invocations might have gone on.
> 
> So here we need the actual number counting whatever optimization was done,
> not the virtual number of shells.  And here I don't think it too bad to have
> the user aware that an optimization was done. When one debugs optimized C
> code in gcc there are corresponding issues that any competent programmer
> just needs to be aware of. Like in-lined functions or statements which
> appear out of order because that's the way assembly code was reorganized.

We'll have to see how this works out; I'm hoping that in fact any time
the debugger is hanging around the subshell won't be optimized out and
the question doesn't arise.  However, if you encounter oddities we can
certainly look at this again.  The trade off between expectation and
reality can be a bit elastic down here.

pws


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-09-06 21:24 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-09-05 14:11 Request: a way to get the subshell level nesting Rocky Bernstein
2008-09-05 19:49 ` Phil Pennock
2008-09-05 19:55   ` Rocky Bernstein
2008-09-05 20:45 ` Peter Stephenson
2008-09-05 21:36   ` Rocky Bernstein
2008-09-06 21:23     ` Peter Stephenson

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