Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > gnu.bash.bug > #16224
| Path | csiph.com!xmission!news.snarked.org!news.linkpendium.com!news.linkpendium.com!panix!usenet.stanford.edu!not-for-mail |
|---|---|
| From | worley@alum.mit.edu (Dale R. Worley) |
| Newsgroups | gnu.bash.bug |
| Subject | Proposed new feature for bash: unbuffered pipes, part 3: bash.diff |
| Date | Tue, 21 Apr 2020 20:39:51 -0400 |
| Lines | 316 |
| Approved | bug-bash@gnu.org |
| Message-ID | <mailman.920.1587516005.3066.bug-bash@gnu.org> (permalink) |
| References | <87ftcwwdyg.fsf@hobgoblin.ariadne.com> |
| NNTP-Posting-Host | lists.gnu.org |
| X-Trace | usenet.stanford.edu 1587516005 13200 209.51.188.17 (22 Apr 2020 00:40:05 GMT) |
| X-Complaints-To | action@cs.stanford.edu |
| To | bug-bash@gnu.org |
| Envelope-to | bug-bash@gnu.org |
| DKIM-Signature | v=1; a=rsa-sha256; c=relaxed/relaxed; d=comcastmailservice.net; s=20180828_2048; t=1587515993; bh=vWOIvu/0mBN3HdiUQAPHJXf5/scVWrlKKDE9aksFhHg=; h=Received:Received:Received:Received:From:To:Subject:Date: Message-ID; b=TbMP8fUa6pxFrcXryZtAyQ0V/iCayBd549iRWuL14qHx29DwUapTJx2uKZ21evEdT kO9aYS9gU+PtfEKzTuElsLlKPGf06KuNC15nZdNMQHJcwufoBKyFuYJD6ghaBhrqe+ KRTucDOJGdoWWf1y0SFgjqUCvP33ZIBwjRrJSLA3gHeENr27yM9yNkjAUdRbV1wiuN 57hLJx8eaIEbyTL39Z6XgNAOhdnxH+gnNAYBlKsWCL75VSQi7GNF+O38cy5p8GNxs5 Hwxzx/bQsP7+UHvG0LpQx7oHBUPhrz92cFQG9XT17xXA3TrUjwHRxySWcAfL4Q0SrF OJg3QimZZunQw== |
| X-Xfinity-VMeta | sc=0.00;st=legit |
| X-Authentication-Warning | hobgoblin.ariadne.com: worley set sender to worley@alum.mit.edu using -f |
| Received-SPF | softfail client-ip=2001:558:fe21:29:69:252:207:37; envelope-from=worley@alum.mit.edu; helo=resqmta-ch2-05v.sys.comcast.net |
| X-detected-operating-system | by eggs.gnu.org: First seen = 2020/04/21 20:39:53 |
| X-ACL-Warn | Detected OS = ??? |
| X-Received-From | 2001:558:fe21:29:69:252:207:37 |
| X-BeenThere | bug-bash@gnu.org |
| X-Mailman-Version | 2.1.23 |
| Precedence | list |
| List-Id | Bug reports for the GNU Bourne Again SHell <bug-bash.gnu.org> |
| List-Unsubscribe | <https://lists.gnu.org/mailman/options/bug-bash>, <mailto:bug-bash-request@gnu.org?subject=unsubscribe> |
| List-Archive | <https://lists.gnu.org/archive/html/bug-bash> |
| List-Post | <mailto:bug-bash@gnu.org> |
| List-Help | <mailto:bug-bash-request@gnu.org?subject=help> |
| List-Subscribe | <https://lists.gnu.org/mailman/listinfo/bug-bash>, <mailto:bug-bash-request@gnu.org?subject=subscribe> |
| X-Mailman-Original-Message-ID | <87ftcwwdyg.fsf@hobgoblin.ariadne.com> |
| Xref | csiph.com gnu.bash.bug:16224 |
Show key headers only | View raw
diff --git a/command.h b/command.h
index 3249516..ef611a4 100644
--- a/command.h
+++ b/command.h
@@ -186,6 +186,7 @@ typedef struct element {
#define CMD_COPROC_SUBSHELL 0x1000
#define CMD_LASTPIPE 0x2000
#define CMD_STDPATH 0x4000 /* use standard path for command lookup */
+#define CMD_STDOUT_UNBUFFERED 0x8000 /* Do not buffer stdout. */
/* What a command looks like. */
typedef struct command {
diff --git a/execute_cmd.c b/execute_cmd.c
index 8b3c83a..61d3647 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -567,6 +567,11 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
volatile char *ofifo_list;
#endif
+#ifdef DRW
+ fprintf(stderr, "execute_command_internal %p %X\n", command, (command ? command->flags : 0));
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
if (breaking || continuing)
return (last_command_exit_value);
if (command == 0 || read_but_dont_execute)
@@ -836,6 +841,8 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
command->value.Simple->flags |= CMD_IGNORE_RETURN;
if (command->flags & CMD_STDIN_REDIR)
command->value.Simple->flags |= CMD_STDIN_REDIR;
+ if (command->flags & CMD_STDOUT_UNBUFFERED)
+ command->value.Simple->flags |= CMD_STDOUT_UNBUFFERED;
line_number_for_err_trap = line_number = command->value.Simple->line;
exec_result =
@@ -2466,6 +2473,11 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
struct fd_bitmap *fd_bitmap;
pid_t lastpid;
+#ifdef DRW
+ fprintf(stderr, "execute_pipeline %p %X\n", command, command->flags);
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
#if defined (JOB_CONTROL)
sigset_t set, oset;
BLOCK_CHILD (set, oset);
@@ -2477,7 +2489,9 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
cmd = command;
while (cmd && cmd->type == cm_connection &&
- cmd->value.Connection && cmd->value.Connection->connector == '|')
+ cmd->value.Connection &&
+ (cmd->value.Connection->connector == '|' ||
+ cmd->value.Connection->connector == GREATER_BAR_GREATER))
{
/* Make a pipeline between the two commands. */
if (pipe (fildes) < 0)
@@ -2551,6 +2565,10 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
dispose_fd_bitmap (fd_bitmap);
discard_unwind_frame ("pipe-file-descriptors");
+ if (cmd->flags & CMD_STDOUT_UNBUFFERED)
+ /* If cmd should not buffer stdout, then cmd...->second should
+ not buffer stdout. */
+ cmd->value.Connection->second->flags |= CMD_STDOUT_UNBUFFERED;
cmd = cmd->value.Connection->second;
}
@@ -2644,6 +2662,11 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
int ignore_return, exec_result, was_error_trap, invert;
volatile int save_line_number;
+#ifdef DRW
+ fprintf(stderr, "execute_connection %p %X\n", command, (command ? command->flags : 0));
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
switch (command->value.Connection->connector)
@@ -4158,6 +4181,16 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
SHELL_VAR *func;
volatile int old_builtin, old_command_builtin;
+#ifdef DRW
+ fprintf(stderr, "execute_simple_command %p %X\n", simple_command, (simple_command ? simple_command->flags : 0));
+ {
+ WORD_LIST *w;
+ for (w = simple_command->words; w; w = w->next)
+ fprintf(stderr, "%s ", w->word->word);
+ fprintf(stderr, "\n");
+ }
+#endif
+
result = EXECUTION_SUCCESS;
special_builtin_failed = builtin_is_special = 0;
command_line = (char *)0;
@@ -5425,6 +5458,25 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
exit (EXECUTION_FAILURE);
}
+#ifdef DRW
+ fprintf(stderr, "execute_disk_command %X '%s'\n", cmdflags, command_line);
+#endif /* DRW */
+ if (cmdflags & CMD_STDOUT_UNBUFFERED)
+ {
+ /* Set the environment to request unbuffered stdout from the new
+ program. */
+ struct stat buf;
+ char value[40];
+ fstat(1, &buf);
+ sprintf(value, "STDOUT_UNBUFFERED=%lu:%lu", (unsigned long) buf.st_dev,
+ (unsigned long) buf.st_ino);
+ maybe_make_export_env ();
+ export_env = add_or_supercede_exported_var (value, 1);
+#ifdef DRW
+ fprintf(stderr, "execute_disk_command set '%s'\n", value);
+#endif /* DRW */
+ }
+
if (async)
interactive = old_interactive;
diff --git a/make_cmd.c b/make_cmd.c
index ecbbfd6..cd8e4c6 100644
--- a/make_cmd.c
+++ b/make_cmd.c
@@ -39,6 +39,7 @@
#include "parser.h"
#include "flags.h"
#include "input.h"
+#include "y.tab.h"
#if defined (JOB_CONTROL)
#include "jobs.h"
@@ -189,11 +190,19 @@ command_connect (com1, com2, connector)
{
CONNECTION *temp;
+ if (connector == GREATER_BAR_GREATER || connector == GREATER_BAR_GREATER_AND)
+ com1->flags |= CMD_STDOUT_UNBUFFERED;
+
temp = (CONNECTION *)xmalloc (sizeof (CONNECTION));
temp->connector = connector;
temp->first = com1;
temp->second = com2;
- return (make_command (cm_connection, (SIMPLE_COM *)temp));
+ COMMAND *c = make_command (cm_connection, (SIMPLE_COM *)temp);
+#ifdef DRW
+ fprintf(stderr, "command_connect com1 = %p %X, com2 = %p %X, c = %p %X, connector = %d\n", com1, (com1 ? com1->flags : 0), com2, (com2 ? com2->flags : 0), c, (c ? c->flags : 0), connector);
+ fprintf(stderr, "%s\n", make_command_string(c));
+#endif
+ return (c);
}
static COMMAND *
diff --git a/parse.y b/parse.y
index 3ff87bc..49c2162 100644
--- a/parse.y
+++ b/parse.y
@@ -214,6 +214,8 @@ static size_t shell_input_line_propsize = 0;
# define set_line_mbstate()
#endif
+static void redirect_stderr_to_stdout __P((COMMAND *));
+
extern int yyerror __P((const char *));
#ifdef DEBUG
@@ -352,6 +354,7 @@ static FILE *yyerrstream;
%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
%token GREATER_BAR BAR_AND
+%token GREATER_BAR_GREATER GREATER_BAR_GREATER_AND
/* The types that the various syntactical units return. */
@@ -375,7 +378,7 @@ static FILE *yyerrstream;
%left '&' ';' '\n' yacc_EOF
%left AND_AND OR_OR
-%right '|' BAR_AND
+%right '|' BAR_AND GREATER_BAR_GREATER GREATER_BAR_GREATER_AND
%%
inputunit: simple_list simple_list_terminator
@@ -1283,29 +1286,18 @@ pipeline_command: pipeline
pipeline: pipeline '|' newline_list pipeline
{ $$ = command_connect ($1, $4, '|'); }
+ | pipeline GREATER_BAR_GREATER newline_list pipeline
+ { $$ = command_connect ($1, $4, GREATER_BAR_GREATER); }
| pipeline BAR_AND newline_list pipeline
{
- /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
- COMMAND *tc;
- REDIRECTEE rd, sd;
- REDIRECT *r;
-
- tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1;
- sd.dest = 2;
- rd.dest = 1;
- r = make_redirection (sd, r_duplicating_output, rd, 0);
- if (tc->redirects)
- {
- register REDIRECT *t;
- for (t = tc->redirects; t->next; t = t->next)
- ;
- t->next = r;
- }
- else
- tc->redirects = r;
-
+ redirect_stderr_to_stdout($1);
$$ = command_connect ($1, $4, '|');
}
+ | pipeline GREATER_BAR_GREATER_AND newline_list pipeline
+ {
+ redirect_stderr_to_stdout($1);
+ $$ = command_connect ($1, $4, GREATER_BAR_GREATER);
+ }
| command
{ $$ = $1; }
;
@@ -1319,6 +1311,31 @@ timespec: TIME
;
%%
+/* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2
+ Similarly, cmd1 >|>& cmd2 is equivalent to cmd1 2>&1 >|> cmd2 */
+static void
+redirect_stderr_to_stdout (pipeline)
+ COMMAND *pipeline;
+{
+ COMMAND *tc;
+ REDIRECTEE rd, sd;
+ REDIRECT *r;
+
+ tc = pipeline->type == cm_simple ? (COMMAND *)pipeline->value.Simple : pipeline;
+ sd.dest = 2;
+ rd.dest = 1;
+ r = make_redirection (sd, r_duplicating_output, rd, 0);
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = r;
+ }
+ else
+ tc->redirects = r;
+}
+
/* Initial size to allocate for tokens, and the
amount to grow them by. */
#define TOKEN_DEFAULT_INITIAL_SIZE 496
@@ -2195,6 +2212,8 @@ STRING_INT_ALIST other_token_alist[] = {
{ "&>>", AND_GREATER_GREATER },
{ "<>", LESS_GREATER },
{ ">|", GREATER_BAR },
+ { ">|>", GREATER_BAR_GREATER },
+ { ">|>&", GREATER_BAR_GREATER_AND },
{ "|&", BAR_AND },
{ "EOF", yacc_EOF },
/* Tokens whose value is the character itself */
@@ -3375,7 +3394,19 @@ itrace("shell_getc: bash_input.location.string = `%s'", bash_input.location.stri
else if MBTEST(character == '<' && peek_char == '>')
return (LESS_GREATER);
else if MBTEST(character == '>' && peek_char == '|')
- return (GREATER_BAR);
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '>')
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '&')
+ return (GREATER_BAR_GREATER_AND);
+ shell_ungetc (peek_char);
+ return (GREATER_BAR_GREATER);
+ }
+ shell_ungetc (peek_char);
+ return (GREATER_BAR);
+ }
else if MBTEST(character == '&' && peek_char == '>')
{
peek_char = shell_getc (1);
@@ -5395,6 +5426,8 @@ reserved_word_acceptable (toksym)
case ESAC:
case FI:
case IF:
+ case GREATER_BAR_GREATER_AND:
+ case GREATER_BAR_GREATER:
case OR_OR:
case SEMI_SEMI:
case SEMI_AND:
diff --git a/print_cmd.c b/print_cmd.c
index 9aa6557..1da3844 100644
--- a/print_cmd.c
+++ b/print_cmd.c
@@ -277,6 +277,12 @@ make_command_string_internal (command)
skip_this_indent++;
break;
+ case GREATER_BAR_GREATER:
+ print_deferred_heredocs (" >|> ");
+ if (command->value.Connection->second)
+ skip_this_indent++;
+ break;
+
case ';':
if (deferred_heredocs == 0)
{
Back to gnu.bash.bug | Previous | Next | Find similar
Proposed new feature for bash: unbuffered pipes, part 3: bash.diff worley@alum.mit.edu (Dale R. Worley) - 2020-04-21 20:39 -0400
csiph-web