aboutsummaryrefslogtreecommitdiff
path: root/toys
diff options
context:
space:
mode:
Diffstat (limited to 'toys')
-rw-r--r--toys/pending/sh.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index 0e7933f6..e26d2791 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -2288,11 +2288,11 @@ static struct sh_process *run_command(void)
struct sh_process *pp = 0;
struct arg_list *delete = 0;
- // Count leading variable assignments and perform any assignment(s)
- for (envlen = 0; envlen<arg->c; envlen++) {
- s = varend(arg->v[envlen]);
- if (s == arg->v[envlen] || *s != '=') break;
- }
+ // Count leading variable assignments
+ for (envlen = 0; envlen<arg->c; envlen++)
+ if ((s = varend(arg->v[envlen])) == arg->v[envlen] || *s != '=') break;
+
+ // perform any assignments
if (envlen) {
struct sh_fcall *ff;
struct sh_vars *vv;
@@ -2309,10 +2309,10 @@ static struct sh_process *run_command(void)
error_msg("%.*s: readonly variable", (int)(varend(s)-s), s);
continue;
}
- if (!vv || (!persist && ff != TT.ff))
+ if (!vv || (!persist && ff != TT.ff && (ff = TT.ff)))
(vv = addvar(s, ff))->flags = VAR_NOFREE|(VAR_GLOBAL*!persist);
if (!(sss = expand_one_arg(s, SEMI_IFS, persist ? 0 : &delete))) {
- if (!pp) pp = xzalloc(sizeof(struct sh_process));
+ if (!pp) pp = xzalloc(sizeof(*pp));
pp->exit = 1;
} else if (persist || sss != s) {
vv->flags &= ~VAR_NOFREE;
@@ -2323,8 +2323,17 @@ static struct sh_process *run_command(void)
}
}
- // Expand command line and do what it says
- if (!pp) pp = expand_redir(arg, envlen, 0);
+ // expand cmdline with _old_ var context, matching bash's order of operations
+ if (!pp) {
+ sss = persist ? 0 : dlist_pop(&TT.ff);
+ pp = expand_redir(arg, envlen, 0);
+ if (!persist) {
+ dlist_add_nomalloc((void *)&TT.ff, (void *)sss);
+ TT.ff = TT.ff->prev;
+ }
+ }
+
+ // Do the thing
if (pp->exit || envlen==arg->c) s = 0; // leave $_ alone
else if (!pp->arg.v) s = ""; // nothing to do but blank $_
else {