Hi,
Below is the patch for the new 'errfail' option.
Please note that this is MINIMAL implementation. It will cover the cases
below. Possible to think about this as replacing every ';' (or new line
line that terminate statements) with '&&' - forcing execution to break.
.
Patch is minimal (less than 15 lines of code changes), and is low-risk -
all changes are conditional on the (global) flag setting. No complex logic,
No write of functions.
Feedback/comments are welcomed.
set -o errfail
function foo { echo A ; false ; echo B ; }
function bar { echo C ; foo ; echo D ; }
# Will print A, return non-zero status
foo
# Return from function on first error
# Will print A, CATCH
foo || { echo CATCH ; }
# Failures will propagate through function calls, unless explicitly "caught"
# Print C A CATCH
bar || echo CATCH
# Fancier: "throw"
function throw { echo "${0##*/}: $@" >& 2 ; false ; }
function foo {
if [ ! -f required-file.txt ] ; then
throw "Missing required file"
fi
echo "YES"
}
Small Letters:
* The errfail does NOT cover "top-level" errors. Only "connected"
statements. Either create a 'main' function, or create a top level block:
On Tue, Jul 5, 2022 at 12:00 AM Lawrence Velázquez <[email protected]> wrote:
> On Mon, Jul 4, 2022, at 3:55 PM, Yair Lenga wrote:
> > I'm sorry - I misunderstood your original comments. I'll prepare the
> > patched version (at least, I would like to add comments before
> > publishing...) , and share it.
> > Where/how can I post it ?
>
> Send it to this list as an attachment [1] with a .txt suffix [2].
>
> [1] Gmail will mangle the patch if you send it inline.
> [2] Alleviates issues with clients on the receiving end.
>
> > I did not see anyone else dropping source
> > code/patches into the group ?
>
> Code contributions are not as common as you might think, given
> bash's prominence.
>
> --
> vq
>
diff -ru orig/bash-master/builtins/set.def new/bash-master/builtins/set.def
--- orig/bash-master/builtins/set.def 2022-01-05 00:03:45.000000000 +0200
+++ new/bash-master/builtins/set.def 2022-07-05 11:54:31.545828400 +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 },
@@ -655,6 +658,7 @@
{
pipefail_opt = 0;
ignoreeof = 0;
+/* errfail_opt = 0 ; errfail IS inherit by sub-shells */
#if defined (STRICT_POSIX)
posixly_correct = 1;
diff -ru orig/bash-master/execute_cmd.c new/bash-master/execute_cmd.c
--- orig/bash-master/execute_cmd.c 2022-01-05 00:03:45.000000000 +0200
+++ new/bash-master/execute_cmd.c 2022-07-05 13:03:18.379533800 +0300
@@ -2706,7 +2706,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,
@@ -2714,10 +2714,15 @@
#endif
QUIT;
- optimize_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_fork (command); /* XXX */
+ exec_result = execute_command_internal
(command->value.Connection->second,
asynchronous, pipe_in, pipe_out,
fds_to_close);
+ } ;
executing_list--;
break;
diff -ru orig/bash-master/flags.c new/bash-master/flags.c
--- orig/bash-master/flags.c 2022-01-05 00:03:45.000000000 +0200
+++ new/bash-master/flags.c 2022-07-05 13:42:12.287799400 +0300
@@ -156,6 +156,12 @@
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 '&&'. Used for improved error handling */
+
+int errfail_opt = 0;
+
/* **************************************************************** */
/* */
/* The Flags ALIST. */
diff -ru orig/bash-master/flags.h new/bash-master/flags.h
--- orig/bash-master/flags.h 2022-01-05 00:03:45.000000000 +0200
+++ new/bash-master/flags.h 2022-07-05 11:25:14.515741700 +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;