* [un]alias, command, fc, getopts, newgrp, readonly, times
* make complex ${var%...} constructs support optional
* make here documents optional
- * set -e (some ash testsuite entries use it, want to adopt those)
*
* Bash compat TODO:
* redirection of stdout+stderr: &> and >&
* therefore we don't show them either.
*/
//usage:#define hush_trivial_usage
-//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
+//usage: "[-enxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
//usage:#define hush_full_usage "\n\n"
//usage: "Unix shell interpreter"
static const char o_opt_strings[] ALIGN1 =
"pipefail\0"
"noexec\0"
+ "errexit\0"
#if ENABLE_HUSH_MODE_X
"xtrace\0"
#endif
enum {
OPT_O_PIPEFAIL,
OPT_O_NOEXEC,
+ OPT_O_ERREXIT,
#if ENABLE_HUSH_MODE_X
OPT_O_XTRACE,
#endif
#else
# define G_saved_tty_pgrp 0
#endif
+ /* How deeply are we in context where "set -e" is ignored */
+ int errexit_depth;
+ /* "set -e" rules (do we follow them correctly?):
+ * Exit if pipe, list, or compound command exits with a non-zero status.
+ * Shell does not exit if failed command is part of condition in
+ * if/while, part of && or || list except the last command, any command
+ * in a pipe but the last, or if the command's return value is being
+ * inverted with !. If a compound command other than a subshell returns a
+ * non-zero status because a command failed while -e was being ignored, the
+ * shell does not exit. A trap on ERR, if set, is executed before the shell
+ * exits [ERR is a bashism].
+ *
+ * If a compound command or function executes in a context where -e is
+ * ignored, none of the commands executed within are affected by the -e
+ * setting. If a compound command or function sets -e while executing in a
+ * context where -e is ignored, that setting does not have any effect until
+ * the compound command or the command containing the function call completes.
+ */
+
char o_opt[NUM_OPT_O];
#if ENABLE_HUSH_MODE_X
# define G_x_mode (G.o_opt[OPT_O_XTRACE])
* and it will match } earlier (not here). */
syntax_error_unexpected_ch(ch);
G.last_exitcode = 2;
- goto parse_error1;
+ goto parse_error2;
default:
if (HUSH_DEBUG)
bb_error_msg_and_die("BUG: unexpected %c\n", ch);
parse_error:
G.last_exitcode = 1;
- parse_error1:
+ parse_error2:
{
struct parse_context *pctx;
IF_HAS_KEYWORDS(struct parse_context *p2;)
/* Go through list of pipes, (maybe) executing them. */
for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
int r;
+ int sv_errexit_depth;
if (G.flag_SIGINT)
break;
IF_HAS_KEYWORDS(rword = pi->res_word;)
debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
rword, cond_code, last_rword);
+
+ sv_errexit_depth = G.errexit_depth;
+ if (IF_HAS_KEYWORDS(rword == RES_IF || rword == RES_ELIF ||)
+ pi->followup != PIPE_SEQ
+ ) {
+ G.errexit_depth++;
+ }
#if ENABLE_HUSH_LOOPS
if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
&& loop_top == NULL /* avoid bumping G.depth_of_loop twice */
check_and_run_traps();
}
+ /* Handle "set -e" */
+ if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
+ debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
+ if (G.errexit_depth == 0)
+ hush_exit(rcode);
+ }
+ G.errexit_depth = sv_errexit_depth;
+
/* Analyze how result affects subsequent commands */
#if ENABLE_HUSH_IF
if (rword == RES_IF || rword == RES_ELIF)
G.o_opt[idx] = state;
break;
}
-/* TODO: set -e
-Exit if pipe, list, or compound command exits with a non-zero status.
-Shell does not exit if failed command is part of condition in
-if/while, part of && or || list except the last command, any command
-in a pipe but the last, or if the command's return value is being
-inverted with !. If a compound command other than a subshell returns a
-non-zero status because a command failed while -e was being ignored, the
-shell does not exit. A trap on ERR, if set, is executed before the shell
-exits [ERR is a bashism].
-
-If a compound command or function executes in a context where -e is
-ignored, none of the commands executed within are affected by the -e
-setting. If a compound command or function sets -e while executing in a
-context where -e is ignored, that setting does not have any effect until
-the compound command or the command containing the function call completes.
-*/
+ case 'e':
+ G.o_opt[OPT_O_ERREXIT] = state;
+ break;
default:
return EXIT_FAILURE;
}
flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
builtin_argc = 0;
while (1) {
- opt = getopt(argc, argv, "+c:xinsl"
+ opt = getopt(argc, argv, "+c:exinsl"
#if !BB_MMU
"<:$:R:V:"
# if ENABLE_HUSH_FUNCTIONS
#endif
case 'n':
case 'x':
+ case 'e':
if (set_mode(1, opt, NULL) == 0) /* no error */
break;
default: