Please find below a patch to allow one to direct the xtrace output of a
shell to an alternate file descriptor. It can be used as such:
$ XTRACE_FD=4 ./bash -x [script] 4>bash.debug
or in a script:
exec 4>bash.debug
XTRACE_FD=4
set -x
who
This is very useful for separating the stderr of the shell and it's
children from the shell's xtrace output.
Please advise if this patch is acceptable and if it will be merged or
whether it needs work or otherwise.
Thanx,
b.
diff -ur bash-3.1/externs.h bash-3.1-xtrace_hack/externs.h
--- bash-3.1/externs.h 2005-11-11 23:10:52.0 -0500
+++ bash-3.1-xtrace_hack/externs.h 2006-07-28 13:49:58.0 -0400
@@ -51,6 +51,7 @@
#endif
/* set -x support */
+extern void set_xtrace_stream __P((void));
extern char *indirection_level_string __P((void));
extern void xtrace_print_assignment __P((char *, char *, int, int));
extern void xtrace_print_word_list __P((WORD_LIST *, int));
diff -ur bash-3.1/flags.c bash-3.1-xtrace_hack/flags.c
--- bash-3.1/flags.c2004-07-16 21:19:42.0 -0400
+++ bash-3.1-xtrace_hack/flags.c2006-07-28 14:41:41.0 -0400
@@ -287,6 +287,10 @@
break;
#endif
+case 'x':
+ if (on_or_off == FLAG_ON)
+ set_xtrace_stream();
+ break;
}
return (old_value);
diff -ur bash-3.1/print_cmd.c bash-3.1-xtrace_hack/print_cmd.c
--- bash-3.1/print_cmd.c2005-07-04 13:05:54.0 -0400
+++ bash-3.1-xtrace_hack/print_cmd.c2006-07-28 15:11:43.0 -0400
@@ -51,6 +51,7 @@
#endif
extern int indirection_level;
+extern FILE *xtrace_stream;
static int indentation;
static int indentation_amount = 4;
@@ -116,6 +117,42 @@
/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */
static char indirection_string[100];
+void
+set_xtrace_stream() {
+ static lastfd = -1;
+ SHELL_VAR *v = find_variable("XTRACE_FD");
+ char *c;
+ int fd;
+
+ if (!v)
+ {
+ xtrace_stream = stderr;
+ return;
+ }
+
+ c = v->value;
+ fd = atoi(c);
+
+ if (fd < 0)
+{
+ report_error (_("invalid descriptor in $XTRACE_FD, using stderr"));
+ xtrace_stream = stderr;
+ return;
+}
+
+ if (fd == lastfd)
+ return;
+
+ if (!(xtrace_stream = fdopen(fd, "a")))
+{
+ report_error (_("invalid file descriptor in $XTRACE_FD, using stderr"));
+ xtrace_stream = stderr;
+ return;
+}
+
+ lastfd = fd;
+}
+
/* Print COMMAND (a command tree) on standard output. */
void
print_command (command)
@@ -380,7 +417,7 @@
char *nval;
if (xflags)
-fprintf (stderr, "%s", indirection_level_string ());
+fprintf (xtrace_stream, "%s", indirection_level_string ());
/* VALUE should not be NULL when this is called. */
if (*value == '\0' || assign_list)
@@ -393,14 +430,14 @@
nval = value;
if (assign_list)
-fprintf (stderr, "%s=(%s)\n", name, nval);
+fprintf (xtrace_stream, "%s=(%s)\n", name, nval);
else
-fprintf (stderr, "%s=%s\n", name, nval);
+fprintf (xtrace_stream, "%s=%s\n", name, nval);
if (nval != value)
FREE (nval);
- fflush (stderr);
+ fflush (xtrace_stream);
}
/* A function to print the words of a simple command when set -x is on. */
@@ -413,29 +450,30 @@
char *t, *x;
if (xtflags)
-fprintf (stderr, "%s", indirection_level_string ());
+fprintf (xtrace_stream, "%s", indirection_level_string ());
for (w = list; w; w = w->next)
{
t = w->word->word;
if (t == 0 || *t == '\0')
- fprintf (stderr, "''%s", w->next ? " " : "");
+ fprintf (xtrace_stream, "''%s", w->next ? " " : "");
else if (sh_contains_shell_metas (t))
{
x = sh_single_quote (t);
- fprintf (stderr, "%s%s", x, w->next ? " " : "");
+ fprintf (xtrace_stream, "%s%s", x, w->next ? " " : "");
free (x);
}
else if (ansic_shouldquote (t))
{
x = ansic_quote (t, 0, (int *)0);
- fprintf (stderr, "%s%s", x, w->next ? " " : "");
+ fprintf (xtrace_stream, "%s%s", x, w->next ? " " : "");
free (x);
}
else
- fprintf (stderr, "%s%s", t, w->next ? " " : "");
+ fprintf (xtrace_stream, "%s%s", t, w->next ? " " : "");
}
- fprintf (stderr, "\n");
+ fprintf (xtrace_stream, "\n");
+ fflush (xtrace_stream);
}
static void
@@ -458,8 +496,8 @@
xtrace_print_for_command_head (for_command)
FOR_COM *for_command;
{
- fprintf (stderr, "%s", indirection_level_string ());
- fprintf (stderr, "for %s in ", for_command->name->word);
+ fprintf (xtrace_stream, "%s", indirection_level_string ());
+ fprintf (xtrace_stream, "for %s in ", for_command->name->word);
xtrace_print_word_list (for_command->map_list, 0);
}
@@ -512,8 +550,8 @@
xtrace_print_select_command_head (select_command)
SELECT_COM *select_command;
{
- fprintf (stderr, "%s", indirection_level_string ());
- fprintf (stderr, "select %s in ", select_command->name