diff -ur orig/bash-devel/builtins/set.def new/bash-devel/builtins/set.def --- orig/bash-devel/builtins/set.def 2022-06-28 23:15:24.000000000 +0300 +++ new/bash-devel/builtins/set.def 2022-07-07 15:37:24.929011000 +0300 @@ -76,6 +76,8 @@ emacs use an emacs-style line editing interface #endif /* READLINE */ errexit same as -e + errfail execution of command lists will stop whenever + a single command return non-zero status errtrace same as -E functrace same as -T hashall same as -h @@ -196,6 +198,7 @@ { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, #endif { "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "errfail", '\0', &errfail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, diff -ur orig/bash-devel/eval.c new/bash-devel/eval.c --- orig/bash-devel/eval.c 2022-06-28 23:15:24.000000000 +0300 +++ new/bash-devel/eval.c 2022-07-08 11:00:01.670123000 +0300 @@ -58,6 +58,7 @@ { int our_indirection_level; COMMAND * volatile current_command; + int cmd_result ; USE_VAR(current_command); @@ -168,7 +169,12 @@ executing = 1; stdin_redir = 0; - execute_command (current_command); + cmd_result = execute_command (current_command); + /* with errfail, failure in commands (non-zero status) + will terminate execution. */ + if ( errfail_opt && cmd_result != EXIT_SUCCESS ) { + EOF_Reached = EOF ; + } ; exec_done: QUIT; diff -ur orig/bash-devel/execute_cmd.c new/bash-devel/execute_cmd.c --- orig/bash-devel/execute_cmd.c 2022-06-28 23:15:24.000000000 +0300 +++ new/bash-devel/execute_cmd.c 2022-07-08 11:46:05.731181500 +0300 @@ -2749,7 +2749,7 @@ QUIT; #if 1 - execute_command (command->value.Connection->first); + exec_result = execute_command (command->value.Connection->first); #else execute_command_internal (command->value.Connection->first, asynchronous, pipe_in, pipe_out, @@ -2757,10 +2757,15 @@ #endif QUIT; - optimize_connection_fork (command); /* XXX */ - exec_result = execute_command_internal (command->value.Connection->second, + + /* With errfail, the ';' is similar to '&&' */ + /* Execute the second part, only if first part was OK */ + if ( !errfail_opt || exec_result == EXECUTION_SUCCESS ) { + optimize_connection_fork (command); /* XXX */ + exec_result = execute_command_internal (command->value.Connection->second, asynchronous, pipe_in, pipe_out, fds_to_close); + } ; executing_list--; break; @@ -2992,6 +2997,11 @@ if (continuing) break; } + + // with errfail - execute a break if the body failed + if ( errfail_opt && retval != EXECUTION_SUCCESS ) { + break ; + } ; } loop_level--; @@ -3164,16 +3174,21 @@ break; } + // with errfail: assume a break if the body failed + if ( errfail_opt && body_status != EXECUTION_SUCCESS ) { + break ; + } ; + /* Evaluate the step expression. */ line_number = arith_lineno; expresult = eval_arith_for_expr (arith_for_command->step, &expok); line_number = save_lineno; if (expok == 0) - { - body_status = EXECUTION_FAILURE; - break; - } + { + body_status = EXECUTION_FAILURE; + break; + } } loop_level--; @@ -3734,6 +3749,12 @@ if (continuing) break; } + + // with errfail: assume a break if the body failed + if ( errfail_opt && body_status != EXECUTION_SUCCESS ) { + break ; + } ; + } loop_level--; diff -ur orig/bash-devel/flags.c new/bash-devel/flags.c --- orig/bash-devel/flags.c 2022-06-28 23:15:24.000000000 +0300 +++ new/bash-devel/flags.c 2022-07-07 15:51:14.899947500 +0300 @@ -156,6 +156,15 @@ with a 0 status, the status of the pipeline is 0. */ int pipefail_opt = 0; +/* Non-zero means that when executing connected commands (';' or new lines) + the sequence will be stopped when any individual commands return a non-zero + status. Similar to '&&'. Also, failure on the loop body will result + in breaking the loop (while, until, for, arith-for). + + Used for improved error handling */ + +int errfail_opt = 0; + /* **************************************************************** */ /* */ /* The Flags ALIST. */ diff -ur orig/bash-devel/flags.h new/bash-devel/flags.h --- orig/bash-devel/flags.h 2022-06-28 23:15:24.000000000 +0300 +++ new/bash-devel/flags.h 2022-07-07 15:51:38.165941100 +0300 @@ -48,7 +48,7 @@ echo_command_at_execute, 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, errfail_opt ; /* -c, -s invocation options -- not really flags, but they show up in $- */ extern int want_pending_command, read_from_stdin;