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

Re: =() and &! don't go together?



On Thu, 25 Aug 2011 13:22:09 +0200
Štěpán Němec <stepnem@xxxxxxxxx> wrote:
> It looks like when &! is used (i.e., "program =(computation) &!"), the
> temporary file created by =() does not exist at the point the command
> tries to access it. Is there a solution to this?

I think the basic problem here is that =(...) uses a temporary file, and
if you've told the shell to forget about the process it's just created
there's nothing to tidy up the temporary file.  I would have guessed it
would simply not tidy up the file at all, however instead it seems it
tidies it up even before it's used, which doesn't seem particularly
useful.

You can work around both problems with

(program =(computation)) &!

In this case, the subshell will hang around to tidy up the temporary
file.

The following patch does what I think is the best we can, namely just
leave the files lying around but document the fact and the workaround.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.139
diff -p -u -r1.139 expn.yo
--- Doc/Zsh/expn.yo	14 Aug 2011 23:19:22 -0000	1.139
+++ Doc/Zsh/expn.yo	28 Aug 2011 16:15:23 -0000
@@ -471,6 +471,18 @@ example(tt({ paste <LPAR()cut -f1) var(f
 The extra processes here are
 spawned from the parent shell which will wait for their completion.
 
+Another problem arises any time a job with a substitution that requires
+a temporary file is disowned by the shell, including the case where
+`tt(&!)' or `tt(&|)' appears at the end of a command containing a
+subsitution.  In that case the temporary file will not be cleaned up as
+the shell no longer has any memory of the job.  A workaround is to use
+a subshell, for example,
+
+example(LPAR()mycmd =(myoutput)RPAR() &!)
+
+as the forked subshell will wait for the command to finish then remove
+the temporary file.
+
 texinode(Parameter Expansion)(Command Substitution)(Process Substitution)(Expansion)
 sect(Parameter Expansion)
 cindex(parameter expansion)
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.203
diff -p -u -r1.203 exec.c
--- Src/exec.c	17 Aug 2011 20:26:05 -0000	1.203
+++ Src/exec.c	28 Aug 2011 16:15:23 -0000
@@ -405,7 +405,7 @@ execcursh(Estate state, int do_exec)
     state->pc++;
 
     if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob))
-	deletejob(jobtab + thisjob);
+	deletejob(jobtab + thisjob, 0);
     cmdpush(CS_CURSH);
     execlist(state, 1, do_exec);
     cmdpop();
@@ -1434,7 +1434,7 @@ execpline(Estate state, wordcode slcode,
 	    zclose(opipe[0]);
 	}
 	if (how & Z_DISOWN) {
-	    deletejob(jobtab + thisjob);
+	    deletejob(jobtab + thisjob, 1);
 	    thisjob = -1;
 	}
 	else
@@ -1484,7 +1484,7 @@ execpline(Estate state, wordcode slcode,
 		    printjob(jn, !!isset(LONGLISTJOBS), 1);
 		}
 		else if (newjob != list_pipe_job)
-		    deletejob(jn);
+		    deletejob(jn, 0);
 		else
 		    lastwj = -1;
 	    }
@@ -1588,7 +1588,7 @@ execpline(Estate state, wordcode slcode,
 
 	    if (list_pipe && (lastval & 0200) && pj >= 0 &&
 		(!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
-		deletejob(jn);
+		deletejob(jn, 0);
 		jn = jobtab + pj;
 		if (jn->gleader)
 		    killjb(jn, lastval & ~0200);
@@ -1596,7 +1596,7 @@ execpline(Estate state, wordcode slcode,
 	    if (list_pipe_child ||
 		((jn->stat & STAT_DONE) &&
 		 (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB)))))
-		deletejob(jn);
+		deletejob(jn, 0);
 	    thisjob = pj;
 
 	}
@@ -4271,7 +4271,7 @@ execshfunc(Shfunc shf, LinkList args)
 	 * would be filled by a recursive function. */
 	last_file_list = jobtab[thisjob].filelist;
 	jobtab[thisjob].filelist = NULL;
-	deletejob(jobtab + thisjob);
+	deletejob(jobtab + thisjob, 0);
     }
 
     if (isset(XTRACE)) {
@@ -4300,7 +4300,7 @@ execshfunc(Shfunc shf, LinkList args)
     cmdsp = ocsp;
 
     if (!list_pipe)
-	deletefilelist(last_file_list);
+	deletefilelist(last_file_list, 0);
 }
 
 /* Function to execute the special type of command that represents an *
Index: Src/jobs.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/jobs.c,v
retrieving revision 1.87
diff -p -u -r1.87 jobs.c
--- Src/jobs.c	16 Aug 2011 15:27:08 -0000	1.87
+++ Src/jobs.c	28 Aug 2011 16:15:23 -0000
@@ -269,7 +269,7 @@ handle_sub(int job, int fg)
 	       sleep, the rest will be executed by a sub-shell,
 	       but the parent shell gets notified for the
 	       sleep.
-	       deletejob(sj); */
+	       deletejob(sj, 0); */
 	    /* If this super-job contains only the sub-shell,
 	       we have to attach the tty to its process group
 	       now. */
@@ -955,7 +955,7 @@ printjob(Job jn, int lng, int synch)
 	if (jn->stat & STAT_DONE) {
 	    if (should_report_time(jn))
 		dumptime(jn);
-	    deletejob(jn);
+	    deletejob(jn, 0);
 	    if (job == curjob) {
 		curjob = prevjob;
 		prevjob = job;
@@ -1085,7 +1085,7 @@ printjob(Job jn, int lng, int synch)
     if (jn->stat & STAT_DONE) {
 	if (should_report_time(jn))
 	    dumptime(jn);
-	deletejob(jn);
+	deletejob(jn, 0);
 	if (job == curjob) {
 	    curjob = prevjob;
 	    prevjob = job;
@@ -1100,12 +1100,13 @@ printjob(Job jn, int lng, int synch)
 
 /**/
 void
-deletefilelist(LinkList file_list)
+deletefilelist(LinkList file_list, int disowning)
 {
     char *s;
     if (file_list) {
 	while ((s = (char *)getlinknode(file_list))) {
-	    unlink(s);
+	    if (!disowning)
+		unlink(s);
 	    zsfree(s);
 	}
 	zfree(file_list, sizeof(struct linklist));
@@ -1141,7 +1142,7 @@ freejob(Job jn, int deleting)
 	/* careful in case we shrink and move the job table */
 	int job = jn - jobtab;
 	if (deleting)
-	    deletejob(jobtab + jn->other);
+	    deletejob(jobtab + jn->other, 0);
 	else
 	    freejob(jobtab + jn->other, 0);
 	jn = jobtab + job;
@@ -1161,13 +1162,17 @@ freejob(Job jn, int deleting)
 /*
  * We are actually finished with this job, rather
  * than freeing it to make space.
+ *
+ * If "disowning" is set, files associated with the job are not
+ * actually deleted --- and won't be as there is nothing left
+ * to clear up.
  */
 
 /**/
 void
-deletejob(Job jn)
+deletejob(Job jn, int disowning)
 {
-    deletefilelist(jn->filelist);
+    deletefilelist(jn->filelist, disowning);
     if (jn->stat & STAT_ATTACH) {
 	attachtty(mypgrp);
 	adjustwinsize(0);
@@ -1343,7 +1348,7 @@ zwaitjob(int job, int wait_cmd)
 	    child_block();
 	}
     } else {
-	deletejob(jn);
+	deletejob(jn, 0);
 	pipestats[0] = lastval;
 	numpipestats = 1;
     }
@@ -1366,7 +1371,7 @@ waitjobs(void)
     if (jn->procs || jn->auxprocs)
 	zwaitjob(thisjob, 0);
     else {
-	deletejob(jn);
+	deletejob(jn, 0);
 	pipestats[0] = lastval;
 	numpipestats = 1;
     }
@@ -1494,7 +1499,7 @@ spawnjob(void)
 	}
     }
     if (!hasprocs(thisjob))
-	deletejob(jobtab + thisjob);
+	deletejob(jobtab + thisjob, 0);
     else
 	jobtab[thisjob].stat |= STAT_LOCKED;
     thisjob = -1;
@@ -2070,7 +2075,7 @@ bin_fg(char *name, char **argv, Options 
 		waitjobs();
 		retval = lastval2;
 	    } else if (ofunc == BIN_DISOWN)
-	        deletejob(jobtab + job);
+	        deletejob(jobtab + job, 1);
 	    break;
 	case BIN_JOBS:
 	    printjob(job + (oldjobtab ? oldjobtab : jobtab), lng, 2);
@@ -2106,7 +2111,7 @@ bin_fg(char *name, char **argv, Options 
 #endif
                          pids);
 	    }
-	    deletejob(jobtab + job);
+	    deletejob(jobtab + job, 1);
 	    break;
 	}
 	thisjob = ocj;
 


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