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