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

Re: curjob in sub-shells?



On Wed 20 May 2026, at 03:42, Peter Stephenson wrote:
> From what I remember about fiddling with this ages aog, it's governed by
> the principle of least surprise: I think the point was that if you're in
> a subshell and reporting the current job the user probably wants to see
> what's in the parent shell.

ty. i think your 'oldjobtab' changes (w/17265) mostly addressed that aspect

here's the change i mentioned + some tests. + removed an uncharacteristic full
stop from an error message

dana


diff --git a/Src/jobs.c b/Src/jobs.c
index fc79a3f3a..2661ea0c1 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1896,21 +1896,19 @@ spawnjob(void)
     Process pn;
 
     DPUTS(thisjob == -1, "No valid job in spawnjob.");
-    /* if we are not in a subshell */
-    if (!subsh) {
-	if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED)) {
-	    curjob = thisjob;
-	    setprevjob();
-	} else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
-	    prevjob = thisjob;
-	if (jobbing && jobtab[thisjob].procs) {
-	    FILE *fout = shout ? shout : stdout;
-	    fprintf(fout, "[%d]", thisjob);
-	    for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
-		fprintf(fout, " %ld", (long) pn->pid);
-	    fprintf(fout, "\n");
-	    fflush(fout);
-	}
+    if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED)) {
+	curjob = thisjob;
+	setprevjob();
+    } else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
+	prevjob = thisjob;
+
+    if (!subsh && jobbing && jobtab[thisjob].procs) {
+	FILE *fout = shout ? shout : stdout;
+	fprintf(fout, "[%d]", thisjob);
+	for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
+	    fprintf(fout, " %ld", (long) pn->pid);
+	fprintf(fout, "\n");
+	fflush(fout);
     }
     if (!hasprocs(thisjob))
 	deletejob(jobtab + thisjob, 0);
@@ -2460,7 +2458,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
 
     if ((func == BIN_FG || func == BIN_BG) && !jobbing) {
 	/* oops... maybe bg and fg should have been disabled? */
-	zwarnnam(name, "no job control in this shell.");
+	zwarnnam(name, "no job control in this shell");
 	return 1;
     }
 
diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index d52888dd9..135869d81 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -193,6 +193,104 @@
 *>\[2]  ? interrupt*sleep*
 *>\[1]  ? kill*sleep*
 
+  zpty_start
+  zpty_input jobs
+  zpty_input '( jobs ); :'
+  zpty_stop
+0:jobs with no jobs
+
+  zpty_start
+  zpty_input 'sleep 2 &; ( jobs ); disown'
+  zpty_stop
+0:jobs in sub-shell with job in parent shell
+*>\[1] <->
+*>\[1]  + * sleep 2
+
+  zpty_start
+  zpty_input '( sleep 2 &; jobs ); :'
+  zpty_stop
+0:jobs in sub-shell with job in same shell
+*>\[2]  + * sleep 2
+
+  zpty_start
+  zpty_input 'sleep 2 &; jobs; ( sleep 3 &; jobs ); jobs; disown'
+  zpty_stop
+0:jobs in sub-shell with job in parent + same shell
+*>\[1] <->
+*>\[1]  + * sleep 2
+*>\[2]  + * sleep 3
+*>\[1]  + * sleep 2
+
+  zpty_start
+  zpty_input '( sleep 2 &; sleep 3 &; jobs ); :'
+  zpty_stop
+0:jobs in sub-shell with two jobs in same shell
+*>\[2]  - * sleep 2
+*>\[3]  + * sleep 3
+
+  zpty_start
+  zpty_input 'sleep 2 &; sleep 3 &; disown; jobs; disown'
+  zpty_stop
+0:disown current job
+*>\[1] <->
+*>\[2] <->
+*>\[1]  + * sleep 2
+
+  zpty_start
+  zpty_input disown
+  zpty_stop
+0:disown with no jobs
+>disown: no current job
+
+  zpty_start
+  zpty_input 'sleep 2 &; ( disown ); jobs; disown'
+  zpty_stop
+0:disown in sub-shell with job in parent shell
+*>\[1] <->
+*>disown: can't manipulate jobs in subshell
+*>\[1]  + * sleep 2
+
+  zpty_start
+  zpty_input '( sleep 3 &; disown; jobs ); :'
+  zpty_stop
+0:disown in sub-shell with job in same shell
+
+  zpty_start
+  zpty_input 'sleep 2 &; ( sleep 3 &; disown; jobs ); jobs; disown'
+  zpty_stop
+0:disown in sub-shell with job in parent + same shell
+*>\[1] <->
+*>\[1]  + * sleep 2
+
+# @todo apparently testing suspended jobs with zpty is error-prone. see above
+#  zpty_start
+#  zpty_input 'sleep 3 &'
+#  zpty_input 'kill -STOP ${${=${ jobs -p }}[3]}'
+#  zpty_input 'disown'
+#  zpty_stop
+#0:disown with stopped job
+#*>\[1] <->
+#*>\[1] * suspended * sleep 3
+#*>disown: warning: job is suspended*
+
+  zpty_start
+  zpty_input 'sleep 2 &; sleep 3 &|; jobs; disown'
+  zpty_input 'sleep 2 &; sleep 3 &!; jobs; disown'
+  zpty_stop
+0:background and disown with &| and &!
+*>\[1] <->
+*>\[1] * sleep 2
+*>\[1] <->
+*>\[1] * sleep 2
+
+  zpty_start
+  zpty_input '( fg ); :'
+  zpty_input '( bg ); :'
+  zpty_stop
+0:fg + bg in sub-shell
+*>fg: no job control in this shell
+*>bg: no job control in this shell
+
 %clean
 
   zmodload -ui zsh/zpty
diff --git a/Test/W03jobparameters.ztst b/Test/W03jobparameters.ztst
index a6f7a09b1..6b2b80d54 100644
--- a/Test/W03jobparameters.ztst
+++ b/Test/W03jobparameters.ztst
@@ -50,8 +50,7 @@
 *>zsh:*SIGHUPed*
 
 # $jobstates refers to a job started in the main shell unless
-# one has been started in the subshell.  In the latter case,
-# the subshell has no job control so the job is not marked as current.
+# one has been started in the subshell.
   zpty_start
   zpty_input "MODULE_PATH=${(q)MODULE_PATH}"
   zpty_input 'sleep 3 &'
@@ -63,7 +62,7 @@
 >main
 *>running:+:*=running
 >sub
-*>running::*=running
+*>running:+:*=running
 *>zsh:*SIGHUPed*
 
 # output from zpty removes empty lines
@@ -75,4 +74,4 @@
 0:$jobstate shows no job started in main shell but one started in subshell
 >main
 >sub
-*>running::*=running
+*>running:+:*=running




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