When debugging a shell script, a useful command is: bash -x script-name
The deficiency of this is that "-x" causes all simple commands in your startup files to be echoed as they are executed, and often this output is a lot longer than the output from the commands in the script. For a long time, I've wanted a variant of -x that only echoed the simple commands after bash is done executing the startup files. I finally did a test implementation, naming a new switch "-X". If it is set at the end of the execution of the startup files, then bash sets "-x", which causes subsequent simple commands to be echoed. I named the new option "-X" as a mnemonic variant of "-x". Its long name is "Xtrace", because I couldn't think of anything better. The code changes are quite simple really. Is this a useful idea? Is there a better way to get an effect like this? Dale diff --git a/builtins/set.def b/builtins/set.def index d2bba43..e71c58f 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -114,6 +114,7 @@ Options: vi use a vi-style line editing interface #endif /* READLINE */ xtrace same as -x + Xtrace same as -X -p Turned on whenever the real and effective user ids do not match. Disables processing of the $ENV file and importing of shell functions. Turning this option off causes the effective uid and @@ -122,6 +123,7 @@ Options: -u Treat unset variables as an error when substituting. -v Print shell input lines as they are read. -x Print commands and their arguments as they are executed. + -X Set -x after startup files are executed. #if defined (BRACE_EXPANSION) -B the shell will perform brace expansion #endif /* BRACE_EXPANSION */ @@ -231,6 +233,7 @@ const struct { { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, #endif { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "Xtrace", 'X', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, }; diff --git a/flags.c b/flags.c index 6e20841..0828f78 100644 --- a/flags.c +++ b/flags.c @@ -159,6 +159,9 @@ int error_trace_mode = 0; with a 0 status, the status of the pipeline is 0. */ int pipefail_opt = 0; +/* Non-zero means set -x after startup files are executed. */ +int echo_commands_after_startup = 0; + /* **************************************************************** */ /* */ /* The Flags ALIST. */ @@ -187,7 +190,7 @@ const struct flags_alist shell_flags[] = { { 't', &just_one_command }, { 'u', &unbound_vars_is_error }, { 'v', &verbose_flag }, - { 'x', &echo_command_at_execute }, + { 'x', &echo_command_at_execute }, /* New flags that control non-standard things. */ #if 0 @@ -204,6 +207,7 @@ const struct flags_alist shell_flags[] = { { 'I', &no_invisible_vars }, { 'P', &no_symbolic_links }, { 'T', &function_trace_mode }, + { 'X', &echo_commands_after_startup }, {0, (int *)NULL} }; diff --git a/flags.h b/flags.h index fdbf7f9..3b6fa8c 100644 --- a/flags.h +++ b/flags.h @@ -48,7 +48,8 @@ extern int echo_command_at_execute, no_invisible_vars, noclobber, hashing_enabled, forced_interactive, privileged_mode, jobs_m_flag, asynchronous_notification, interactive_comments, no_symbolic_links, - function_trace_mode, error_trace_mode, pipefail_opt; + function_trace_mode, error_trace_mode, pipefail_opt, + echo_commands_after_startup; /* -c, -s invocation options -- not really flags, but they show up in $- */ extern int want_pending_command, read_from_stdin; diff --git a/shell.c b/shell.c index a2b2a55..4c40cd4 100644 --- a/shell.c +++ b/shell.c @@ -731,6 +731,10 @@ main (argc, argv, env) start_debugger (); #if defined (ONESHOT) + if (echo_commands_after_startup) { + set_minus_o_option (FLAG_ON, "xtrace"); + set_shellopts (); + } executing = 1; run_one_command (command_execution_string); exit_shell (last_command_exit_value); @@ -791,6 +795,11 @@ main (argc, argv, env) read_and_execute: #endif /* !ONESHOT */ + if (echo_commands_after_startup) { + set_minus_o_option (FLAG_ON, "xtrace"); + set_shellopts (); + } + shell_initialized = 1; if (pretty_print_mode && interactive_shell)