ash: eval: Return status in eval functions
Backported from dash: eval: Return status in eval functions The exit status is currently clobbered too early for case statements and loops. This patch fixes it by making the eval functions return the current exit status and setting them in one place -- evaltree. Harald van Dijk pointed out a number of bugs in the original patch. function old new delta evalcommand 1226 1242 +16 cmdloop 383 398 +15 evalfor 223 227 +4 evalcase 271 275 +4 localcmd 348 350 +2 evaltreenr 927 928 +1 evaltree 927 928 +1 evalsubshell 150 151 +1 evalpipe 356 357 +1 parse_command 1585 1584 -1 evalloop 177 164 -13 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 9/2 up/down: 45/-14) Total: 31 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
1c32e49bdf
commit
eb17b6f6c9
132
shell/ash.c
132
shell/ash.c
@ -5864,7 +5864,7 @@ struct backcmd { /* result of evalbackcmd */
|
|||||||
/* These forward decls are needed to use "eval" code for backticks handling: */
|
/* These forward decls are needed to use "eval" code for backticks handling: */
|
||||||
static uint8_t back_exitstatus; /* exit status of backquoted command */
|
static uint8_t back_exitstatus; /* exit status of backquoted command */
|
||||||
#define EV_EXIT 01 /* exit after evaluating tree */
|
#define EV_EXIT 01 /* exit after evaluating tree */
|
||||||
static void evaltree(union node *, int);
|
static int evaltree(union node *, int);
|
||||||
|
|
||||||
static void FAST_FUNC
|
static void FAST_FUNC
|
||||||
evalbackcmd(union node *n, struct backcmd *result)
|
evalbackcmd(union node *n, struct backcmd *result)
|
||||||
@ -8412,13 +8412,13 @@ dotrap(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* forward declarations - evaluation is fairly recursive business... */
|
/* forward declarations - evaluation is fairly recursive business... */
|
||||||
static void evalloop(union node *, int);
|
static int evalloop(union node *, int);
|
||||||
static void evalfor(union node *, int);
|
static int evalfor(union node *, int);
|
||||||
static void evalcase(union node *, int);
|
static int evalcase(union node *, int);
|
||||||
static void evalsubshell(union node *, int);
|
static int evalsubshell(union node *, int);
|
||||||
static void expredir(union node *);
|
static void expredir(union node *);
|
||||||
static void evalpipe(union node *, int);
|
static int evalpipe(union node *, int);
|
||||||
static void evalcommand(union node *, int);
|
static int evalcommand(union node *, int);
|
||||||
static int evalbltin(const struct builtincmd *, int, char **);
|
static int evalbltin(const struct builtincmd *, int, char **);
|
||||||
static void prehash(union node *);
|
static void prehash(union node *);
|
||||||
|
|
||||||
@ -8426,14 +8426,14 @@ static void prehash(union node *);
|
|||||||
* Evaluate a parse tree. The value is left in the global variable
|
* Evaluate a parse tree. The value is left in the global variable
|
||||||
* exitstatus.
|
* exitstatus.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
evaltree(union node *n, int flags)
|
evaltree(union node *n, int flags)
|
||||||
{
|
{
|
||||||
struct jmploc *volatile savehandler = exception_handler;
|
struct jmploc *volatile savehandler = exception_handler;
|
||||||
struct jmploc jmploc;
|
struct jmploc jmploc;
|
||||||
int checkexit = 0;
|
int checkexit = 0;
|
||||||
void (*evalfn)(union node *, int);
|
int (*evalfn)(union node *, int);
|
||||||
int status;
|
int status = 0;
|
||||||
int int_level;
|
int int_level;
|
||||||
|
|
||||||
SAVE_INT(int_level);
|
SAVE_INT(int_level);
|
||||||
@ -8470,15 +8470,13 @@ evaltree(union node *n, int flags)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case NNOT:
|
case NNOT:
|
||||||
evaltree(n->nnot.com, EV_TESTED);
|
status = !evaltree(n->nnot.com, EV_TESTED);
|
||||||
status = !exitstatus;
|
|
||||||
goto setstatus;
|
goto setstatus;
|
||||||
case NREDIR:
|
case NREDIR:
|
||||||
expredir(n->nredir.redirect);
|
expredir(n->nredir.redirect);
|
||||||
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
|
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
evaltree(n->nredir.n, flags & EV_TESTED);
|
status = evaltree(n->nredir.n, flags & EV_TESTED);
|
||||||
status = exitstatus;
|
|
||||||
}
|
}
|
||||||
popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
|
popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
|
||||||
goto setstatus;
|
goto setstatus;
|
||||||
@ -8518,27 +8516,24 @@ evaltree(union node *n, int flags)
|
|||||||
#error NOR + 1 != NSEMI
|
#error NOR + 1 != NSEMI
|
||||||
#endif
|
#endif
|
||||||
unsigned is_or = n->type - NAND;
|
unsigned is_or = n->type - NAND;
|
||||||
evaltree(
|
status = evaltree(
|
||||||
n->nbinary.ch1,
|
n->nbinary.ch1,
|
||||||
(flags | ((is_or >> 1) - 1)) & EV_TESTED
|
(flags | ((is_or >> 1) - 1)) & EV_TESTED
|
||||||
);
|
);
|
||||||
if ((!exitstatus) == is_or)
|
if (!status == is_or || evalskip)
|
||||||
break;
|
break;
|
||||||
if (!evalskip) {
|
|
||||||
n = n->nbinary.ch2;
|
n = n->nbinary.ch2;
|
||||||
evaln:
|
evaln:
|
||||||
evalfn = evaltree;
|
evalfn = evaltree;
|
||||||
calleval:
|
calleval:
|
||||||
evalfn(n, flags);
|
status = evalfn(n, flags);
|
||||||
break;
|
goto setstatus;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case NIF:
|
case NIF:
|
||||||
evaltree(n->nif.test, EV_TESTED);
|
status = evaltree(n->nif.test, EV_TESTED);
|
||||||
if (evalskip)
|
if (evalskip)
|
||||||
break;
|
break;
|
||||||
if (exitstatus == 0) {
|
if (!status) {
|
||||||
n = n->nif.ifpart;
|
n = n->nif.ifpart;
|
||||||
goto evaln;
|
goto evaln;
|
||||||
}
|
}
|
||||||
@ -8546,11 +8541,14 @@ evaltree(union node *n, int flags)
|
|||||||
n = n->nif.elsepart;
|
n = n->nif.elsepart;
|
||||||
goto evaln;
|
goto evaln;
|
||||||
}
|
}
|
||||||
goto success;
|
status = 0;
|
||||||
|
goto setstatus;
|
||||||
case NDEFUN:
|
case NDEFUN:
|
||||||
defun(n->narg.text, n->narg.next);
|
defun(n->narg.text, n->narg.next);
|
||||||
success:
|
/* Not necessary. To test it:
|
||||||
status = 0;
|
* "false; f() { qwerty; }; echo $?" should print 0.
|
||||||
|
*/
|
||||||
|
/* status = 0; */
|
||||||
setstatus:
|
setstatus:
|
||||||
exitstatus = status;
|
exitstatus = status;
|
||||||
break;
|
break;
|
||||||
@ -8565,7 +8563,7 @@ evaltree(union node *n, int flags)
|
|||||||
*/
|
*/
|
||||||
if (pending_sig && dotrap())
|
if (pending_sig && dotrap())
|
||||||
goto exexit;
|
goto exexit;
|
||||||
if (checkexit & exitstatus)
|
if (checkexit & status)
|
||||||
evalskip |= SKIPEVAL;
|
evalskip |= SKIPEVAL;
|
||||||
|
|
||||||
if (flags & EV_EXIT) {
|
if (flags & EV_EXIT) {
|
||||||
@ -8575,14 +8573,16 @@ evaltree(union node *n, int flags)
|
|||||||
|
|
||||||
RESTORE_INT(int_level);
|
RESTORE_INT(int_level);
|
||||||
TRACE(("leaving evaltree (no interrupts)\n"));
|
TRACE(("leaving evaltree (no interrupts)\n"));
|
||||||
|
|
||||||
|
return exitstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
|
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
|
int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
|
||||||
|
|
||||||
static void
|
static int
|
||||||
evalloop(union node *n, int flags)
|
evalloop(union node *n, int flags)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
@ -8593,7 +8593,7 @@ evalloop(union node *n, int flags)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
evaltree(n->nbinary.ch1, EV_TESTED);
|
i = evaltree(n->nbinary.ch1, EV_TESTED);
|
||||||
if (evalskip) {
|
if (evalskip) {
|
||||||
skipping:
|
skipping:
|
||||||
if (evalskip == SKIPCONT && --skipcount <= 0) {
|
if (evalskip == SKIPCONT && --skipcount <= 0) {
|
||||||
@ -8604,27 +8604,28 @@ evalloop(union node *n, int flags)
|
|||||||
evalskip = 0;
|
evalskip = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i = exitstatus;
|
|
||||||
if (n->type != NWHILE)
|
if (n->type != NWHILE)
|
||||||
i = !i;
|
i = !i;
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
break;
|
break;
|
||||||
evaltree(n->nbinary.ch2, flags);
|
status = evaltree(n->nbinary.ch2, flags);
|
||||||
status = exitstatus;
|
|
||||||
if (evalskip)
|
if (evalskip)
|
||||||
goto skipping;
|
goto skipping;
|
||||||
}
|
}
|
||||||
loopnest--;
|
|
||||||
exitstatus = status;
|
exitstatus = status;
|
||||||
|
loopnest--;
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
evalfor(union node *n, int flags)
|
evalfor(union node *n, int flags)
|
||||||
{
|
{
|
||||||
struct arglist arglist;
|
struct arglist arglist;
|
||||||
union node *argp;
|
union node *argp;
|
||||||
struct strlist *sp;
|
struct strlist *sp;
|
||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
arglist.list = NULL;
|
arglist.list = NULL;
|
||||||
@ -8637,12 +8638,11 @@ evalfor(union node *n, int flags)
|
|||||||
}
|
}
|
||||||
*arglist.lastp = NULL;
|
*arglist.lastp = NULL;
|
||||||
|
|
||||||
exitstatus = 0;
|
|
||||||
loopnest++;
|
loopnest++;
|
||||||
flags &= EV_TESTED;
|
flags &= EV_TESTED;
|
||||||
for (sp = arglist.list; sp; sp = sp->next) {
|
for (sp = arglist.list; sp; sp = sp->next) {
|
||||||
setvar0(n->nfor.var, sp->text);
|
setvar0(n->nfor.var, sp->text);
|
||||||
evaltree(n->nfor.body, flags);
|
status = evaltree(n->nfor.body, flags);
|
||||||
if (evalskip) {
|
if (evalskip) {
|
||||||
if (evalskip == SKIPCONT && --skipcount <= 0) {
|
if (evalskip == SKIPCONT && --skipcount <= 0) {
|
||||||
evalskip = 0;
|
evalskip = 0;
|
||||||
@ -8656,26 +8656,32 @@ evalfor(union node *n, int flags)
|
|||||||
loopnest--;
|
loopnest--;
|
||||||
out:
|
out:
|
||||||
popstackmark(&smark);
|
popstackmark(&smark);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
evalcase(union node *n, int flags)
|
evalcase(union node *n, int flags)
|
||||||
{
|
{
|
||||||
union node *cp;
|
union node *cp;
|
||||||
union node *patp;
|
union node *patp;
|
||||||
struct arglist arglist;
|
struct arglist arglist;
|
||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
arglist.list = NULL;
|
arglist.list = NULL;
|
||||||
arglist.lastp = &arglist.list;
|
arglist.lastp = &arglist.list;
|
||||||
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
|
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
|
||||||
exitstatus = 0;
|
|
||||||
for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
|
for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
|
||||||
for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
|
for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
|
||||||
if (casematch(patp, arglist.list->text)) {
|
if (casematch(patp, arglist.list->text)) {
|
||||||
if (evalskip == 0) {
|
/* Ensure body is non-empty as otherwise
|
||||||
evaltree(cp->nclist.body, flags);
|
* EV_EXIT may prevent us from setting the
|
||||||
|
* exit status.
|
||||||
|
*/
|
||||||
|
if (evalskip == 0 && cp->nclist.body) {
|
||||||
|
status = evaltree(cp->nclist.body, flags);
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -8683,12 +8689,14 @@ evalcase(union node *n, int flags)
|
|||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
popstackmark(&smark);
|
popstackmark(&smark);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kick off a subshell to evaluate a tree.
|
* Kick off a subshell to evaluate a tree.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
evalsubshell(union node *n, int flags)
|
evalsubshell(union node *n, int flags)
|
||||||
{
|
{
|
||||||
struct job *jp;
|
struct job *jp;
|
||||||
@ -8714,8 +8722,8 @@ evalsubshell(union node *n, int flags)
|
|||||||
status = 0;
|
status = 0;
|
||||||
if (!backgnd)
|
if (!backgnd)
|
||||||
status = waitforjob(jp);
|
status = waitforjob(jp);
|
||||||
exitstatus = status;
|
|
||||||
INT_ON;
|
INT_ON;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -8788,7 +8796,7 @@ expredir(union node *n)
|
|||||||
* of the shell, which make the last process in a pipeline the parent
|
* of the shell, which make the last process in a pipeline the parent
|
||||||
* of all the rest.)
|
* of all the rest.)
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
evalpipe(union node *n, int flags)
|
evalpipe(union node *n, int flags)
|
||||||
{
|
{
|
||||||
struct job *jp;
|
struct job *jp;
|
||||||
@ -8796,6 +8804,7 @@ evalpipe(union node *n, int flags)
|
|||||||
int pipelen;
|
int pipelen;
|
||||||
int prevfd;
|
int prevfd;
|
||||||
int pip[2];
|
int pip[2];
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
TRACE(("evalpipe(0x%lx) called\n", (long)n));
|
TRACE(("evalpipe(0x%lx) called\n", (long)n));
|
||||||
pipelen = 0;
|
pipelen = 0;
|
||||||
@ -8838,10 +8847,12 @@ evalpipe(union node *n, int flags)
|
|||||||
close(pip[1]);
|
close(pip[1]);
|
||||||
}
|
}
|
||||||
if (n->npipe.pipe_backgnd == 0) {
|
if (n->npipe.pipe_backgnd == 0) {
|
||||||
exitstatus = waitforjob(jp);
|
status = waitforjob(jp);
|
||||||
TRACE(("evalpipe: job done exit status %d\n", exitstatus));
|
TRACE(("evalpipe: job done exit status %d\n", status));
|
||||||
}
|
}
|
||||||
INT_ON;
|
INT_ON;
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -9328,7 +9339,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
* as POSIX mandates */
|
* as POSIX mandates */
|
||||||
return back_exitstatus;
|
return back_exitstatus;
|
||||||
}
|
}
|
||||||
static void
|
static int
|
||||||
evalcommand(union node *cmd, int flags)
|
evalcommand(union node *cmd, int flags)
|
||||||
{
|
{
|
||||||
static const struct builtincmd null_bltin = {
|
static const struct builtincmd null_bltin = {
|
||||||
@ -9511,9 +9522,9 @@ evalcommand(union node *cmd, int flags)
|
|||||||
jp = makejob(/*cmd,*/ 1);
|
jp = makejob(/*cmd,*/ 1);
|
||||||
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
||||||
/* parent */
|
/* parent */
|
||||||
exitstatus = waitforjob(jp);
|
status = waitforjob(jp);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
TRACE(("forked child exited with %d\n", exitstatus));
|
TRACE(("forked child exited with %d\n", status));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* child */
|
/* child */
|
||||||
@ -9559,7 +9570,7 @@ evalcommand(union node *cmd, int flags)
|
|||||||
}
|
}
|
||||||
FORCE_INT_ON;
|
FORCE_INT_ON;
|
||||||
}
|
}
|
||||||
break;
|
goto readstatus;
|
||||||
|
|
||||||
case CMDFUNCTION:
|
case CMDFUNCTION:
|
||||||
listsetvar(varlist.list, 0);
|
listsetvar(varlist.list, 0);
|
||||||
@ -9567,6 +9578,8 @@ evalcommand(union node *cmd, int flags)
|
|||||||
dowait(DOWAIT_NONBLOCK, NULL);
|
dowait(DOWAIT_NONBLOCK, NULL);
|
||||||
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
||||||
goto raise;
|
goto raise;
|
||||||
|
readstatus:
|
||||||
|
status = exitstatus;
|
||||||
break;
|
break;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
|
|
||||||
@ -9580,6 +9593,8 @@ evalcommand(union node *cmd, int flags)
|
|||||||
setvar0("_", lastarg);
|
setvar0("_", lastarg);
|
||||||
}
|
}
|
||||||
popstackmark(&smark);
|
popstackmark(&smark);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -12205,13 +12220,18 @@ evalstring(char *s, int mask)
|
|||||||
union node *n;
|
union node *n;
|
||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
int skip;
|
int skip;
|
||||||
|
// int status;
|
||||||
|
|
||||||
setinputstring(s);
|
setinputstring(s);
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
|
|
||||||
skip = 0;
|
skip = 0;
|
||||||
while ((n = parsecmd(0)) != NODE_EOF) {
|
while ((n = parsecmd(0)) != NODE_EOF) {
|
||||||
evaltree(n, 0);
|
int i;
|
||||||
|
|
||||||
|
i = evaltree(n, 0);
|
||||||
|
// if (n)
|
||||||
|
// status = i;
|
||||||
popstackmark(&smark);
|
popstackmark(&smark);
|
||||||
skip = evalskip;
|
skip = evalskip;
|
||||||
if (skip)
|
if (skip)
|
||||||
@ -12222,6 +12242,7 @@ evalstring(char *s, int mask)
|
|||||||
skip &= mask;
|
skip &= mask;
|
||||||
evalskip = skip;
|
evalskip = skip;
|
||||||
return skip;
|
return skip;
|
||||||
|
// return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -12264,6 +12285,7 @@ cmdloop(int top)
|
|||||||
union node *n;
|
union node *n;
|
||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
int inter;
|
int inter;
|
||||||
|
int status = 0;
|
||||||
int numeof = 0;
|
int numeof = 0;
|
||||||
|
|
||||||
TRACE(("cmdloop(%d) called\n", top));
|
TRACE(("cmdloop(%d) called\n", top));
|
||||||
@ -12295,10 +12317,14 @@ cmdloop(int top)
|
|||||||
}
|
}
|
||||||
numeof++;
|
numeof++;
|
||||||
} else if (nflag == 0) {
|
} else if (nflag == 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
/* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
|
/* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
|
||||||
job_warning >>= 1;
|
job_warning >>= 1;
|
||||||
numeof = 0;
|
numeof = 0;
|
||||||
evaltree(n, 0);
|
i = evaltree(n, 0);
|
||||||
|
if (n)
|
||||||
|
status = i;
|
||||||
}
|
}
|
||||||
popstackmark(&smark);
|
popstackmark(&smark);
|
||||||
skip = evalskip;
|
skip = evalskip;
|
||||||
@ -12308,7 +12334,7 @@ cmdloop(int top)
|
|||||||
return skip & SKIPEVAL;
|
return skip & SKIPEVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
2
shell/ash_test/ash-misc/exitcode1.right
Normal file
2
shell/ash_test/ash-misc/exitcode1.right
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
One:1
|
||||||
|
Zero:0
|
2
shell/ash_test/ash-misc/exitcode1.tests
Executable file
2
shell/ash_test/ash-misc/exitcode1.tests
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
false || case a in a) echo One:$?;; esac
|
||||||
|
echo Zero:$?
|
2
shell/hush_test/hush-misc/exitcode1.right
Normal file
2
shell/hush_test/hush-misc/exitcode1.right
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
One:1
|
||||||
|
Zero:0
|
2
shell/hush_test/hush-misc/exitcode1.tests
Executable file
2
shell/hush_test/hush-misc/exitcode1.tests
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
false || case a in a) echo One:$?;; esac
|
||||||
|
echo Zero:$?
|
Loading…
Reference in New Issue
Block a user