diff options
-rw-r--r-- | hush.c | 30 | ||||
-rw-r--r-- | shell/hush.c | 30 | ||||
-rw-r--r-- | tests/sh.testcases | 29 |
3 files changed, 61 insertions, 28 deletions
@@ -1326,19 +1326,18 @@ static int run_pipe_real(struct pipe *pi) * Builtins within pipes have to fork anyway, and are handled in * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. */ - if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { - child = & (pi->progs[0]); - if (child->group && ! child->subshell) { - int squirrel[] = {-1, -1, -1}; - int rcode; - debug_printf("non-subshell grouping\n"); - setup_redirects(child, squirrel); - /* XXX could we merge code with following builtin case, - * by creating a pseudo builtin that calls run_list_real? */ - rcode = run_list_real(child->group); - restore_redirects(squirrel); - return rcode; - } + if (pi->num_progs == 1) child = & (pi->progs[0]); + if (pi->num_progs == 1 && child->group && child->subshell == 0) { + int squirrel[] = {-1, -1, -1}; + int rcode; + debug_printf("non-subshell grouping\n"); + setup_redirects(child, squirrel); + /* XXX could we merge code with following builtin case, + * by creating a pseudo builtin that calls run_list_real? */ + rcode = run_list_real(child->group); + restore_redirects(squirrel); + return rcode; + } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } if (i!=0 && child->argv[i]==NULL) { /* assignments, but no command: set the local environment */ @@ -1352,7 +1351,8 @@ static int run_pipe_real(struct pipe *pi) * variable. */ int export_me=0; char *name, *value; - name = strdup(child->argv[i]); + name = xstrdup(child->argv[i]); + debug_printf("Local environment set: %s\n", name); value = strchr(name, '='); if (value) *value=0; @@ -1478,6 +1478,7 @@ static int run_list_real(struct pipe *pi) if (rmode == RES_ELIF && !if_code) continue; if (pi->num_progs == 0) continue; rcode = run_pipe_real(pi); + debug_printf("run_pipe_real returned %d\n",rcode); if (rcode!=-1) { /* We only ran a builtin: rcode was set by the return value * of run_pipe_real(), and we don't need to wait for anything. */ @@ -1943,6 +1944,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) debug_printf("pop stack\n"); old = ctx->stack; old->child->group = ctx->list_head; + old->child->subshell = 0; *ctx = *old; /* physical copy */ free(old); } diff --git a/shell/hush.c b/shell/hush.c index 126f9da..3b1e53c 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1326,19 +1326,18 @@ static int run_pipe_real(struct pipe *pi) * Builtins within pipes have to fork anyway, and are handled in * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. */ - if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { - child = & (pi->progs[0]); - if (child->group && ! child->subshell) { - int squirrel[] = {-1, -1, -1}; - int rcode; - debug_printf("non-subshell grouping\n"); - setup_redirects(child, squirrel); - /* XXX could we merge code with following builtin case, - * by creating a pseudo builtin that calls run_list_real? */ - rcode = run_list_real(child->group); - restore_redirects(squirrel); - return rcode; - } + if (pi->num_progs == 1) child = & (pi->progs[0]); + if (pi->num_progs == 1 && child->group && child->subshell == 0) { + int squirrel[] = {-1, -1, -1}; + int rcode; + debug_printf("non-subshell grouping\n"); + setup_redirects(child, squirrel); + /* XXX could we merge code with following builtin case, + * by creating a pseudo builtin that calls run_list_real? */ + rcode = run_list_real(child->group); + restore_redirects(squirrel); + return rcode; + } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } if (i!=0 && child->argv[i]==NULL) { /* assignments, but no command: set the local environment */ @@ -1352,7 +1351,8 @@ static int run_pipe_real(struct pipe *pi) * variable. */ int export_me=0; char *name, *value; - name = strdup(child->argv[i]); + name = xstrdup(child->argv[i]); + debug_printf("Local environment set: %s\n", name); value = strchr(name, '='); if (value) *value=0; @@ -1478,6 +1478,7 @@ static int run_list_real(struct pipe *pi) if (rmode == RES_ELIF && !if_code) continue; if (pi->num_progs == 0) continue; rcode = run_pipe_real(pi); + debug_printf("run_pipe_real returned %d\n",rcode); if (rcode!=-1) { /* We only ran a builtin: rcode was set by the return value * of run_pipe_real(), and we don't need to wait for anything. */ @@ -1943,6 +1944,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) debug_printf("pop stack\n"); old = ctx->stack; old->child->group = ctx->list_head; + old->child->subshell = 0; *ctx = *old; /* physical copy */ free(old); } diff --git a/tests/sh.testcases b/tests/sh.testcases index 88e709f..e2a7587 100644 --- a/tests/sh.testcases +++ b/tests/sh.testcases @@ -28,6 +28,35 @@ if false; then tr 'A-Z' 'a-z'; else echo bar4; fi <foo if true || false; then echo foo; else echo bar5; fi if true && false; then echo bar6; else echo foo; fi +# basic distinction between local and env variables +unset FOO +FOO=bar env | grep FOO +echo "but not here: $FOO" +FOO=bar +env | grep FOO +echo "yes, here: $FOO" +FOO= +echo a $FOO b +echo "a $FOO b" + +# not quite so basic variables. Credit to Matt Kraai. +unset FOO +FOO=bar +export FOO +env | grep FOO +unset FOO +export FOO=bar +FOO=baz +env | grep FOO + +# interaction between environment variables and if/then and subshells +FOO=default +if true; then FOO=new; fi +echo $FOO +FOO=default +(FOO=bogus) +echo $FOO + # make sure we can duplicate file descriptors properly echo replacement >foo 2>&1 cat foo |