On Wed, Jun 23, 2010 at 10:00:12AM +0200, Werner Fink wrote:
> On Tue, Jun 22, 2010 at 04:50:54PM -0400, Chet Ramey wrote:
> > On 6/18/10 10:05 AM, Dr. Werner Fink wrote:
> > 
> > > as now is visible the last command in the pipe sequence done
> > > in the bash is a real sub process whereas in the ksh it is not.
> > > 
> > > The question rises: Why does the bash require a sub peocess/shell
> > > for the final command of a pipe sequence.
> > 
> > It's an implementation decision: the code as it exists today is more
> > straightforward.  Since Posix requires that all commands in a pipeline
> > be executed in a subshell environment, though it allows the ksh behavior
> > as an extension, there's been no requirement to change it.
> > 
> > If anyone would like to take a shot at changing the code to not fork when
> > executing a command with a pipe for stdin, I'd be glad to take a look at
> > the result.
> 
> OK ... after a deeper look into execute_cmd.c I'd like to suggest
> something like in the attachment.  Anyone around with a better
> solution? Maybe there is a way to emulate the first pipe commands
> as a named fifo for the last element of the pipe which may avoid
> moving stdin around.  Anyway the patch makes things like:
> 
>  bash/bash-4.1> ./bash -c 'echo a b | while read x y; do a=$x b=$y; done; 
> echo $a $b'
>  a b
>  bash/bash-4.1> ./bash -c 'echo a b | read a b ; echo $a $b'
>  a b
> 
> work.  The change of sh_coproc is simply to avoid a (correct)
> compiler warning.

Yet an other version of the patch to avoid trouble with the
coproc builtin tested out in tests/coproc.tests.  There is one
difference more with tests/redir.tests at

  exit 3 | $EXIT > $TMPDIR/null-redir-e
  echo $? -- ${pipestat...@]}
  testf $TMPDIR/null-redir-e

  exit 4 | > $TMPDIR/null-redir-f
  echo $? -- ${pipestat...@]}
  testf $TMPDIR/null-redir-f

which now reports

  0 -- 3 0
  0 -- 4 0

instead of

  0 -- 0
  0 -- 0

but seems to me ok.


   Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr
--- execute_cmd.c
+++ execute_cmd.c	2010-06-23 12:00:06.870925148 +0200
@@ -1525,7 +1525,7 @@ static struct cpelement *cpl_search __P(
 static struct cpelement *cpl_searchbyname __P((char *));
 static void cpl_prune __P((void));
 
-Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0 };
+Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0, 0, 0 };
 
 cplist_t coproc_list = {0, 0, 0};
 
@@ -2047,13 +2047,19 @@ execute_coproc (command, pipe_in, pipe_o
 }
 #endif
 
+static void restore_stdin(int lstdin)
+{
+  dup2(lstdin, 0);
+  close(lstdin);
+}
+
 static int
 execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
      COMMAND *command;
      int asynchronous, pipe_in, pipe_out;
      struct fd_bitmap *fds_to_close;
 {
-  int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result;
+  int lstdin, prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result;
   COMMAND *cmd;
   struct fd_bitmap *fd_bitmap;
 
@@ -2148,11 +2154,36 @@ execute_pipeline (command, asynchronous,
   /* Now execute the rightmost command in the pipeline.  */
   if (ignore_return && cmd)
     cmd->flags |= CMD_IGNORE_RETURN;
+
+  begin_unwind_frame ("pipe-file-descriptors");
+  lstdin = -1;
+  if (!asynchronous && pipe_out == NO_PIPE && prev > 0)
+    {
+      lstdin = move_to_high_fd(0, 0, 255);
+      if (lstdin > 0)
+	{
+	  dup2(prev, 0);
+	  close(prev);
+	  prev = NO_PIPE;
+	  add_unwind_protect (restore_stdin, lstdin);
+	}
+    }
+  if (prev >= 0)
+    add_unwind_protect (close, prev);
+
   exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close);
 
+  if (lstdin > 0)
+    {
+      dup2(lstdin, 0);
+      close(lstdin);
+    }
+
   if (prev >= 0)
     close (prev);
 
+  discard_unwind_frame ("pipe-file-descriptors");
+
 #if defined (JOB_CONTROL)
   UNBLOCK_CHILD (oset);
 #endif

Reply via email to