aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hush.c30
-rw-r--r--shell/hush.c30
-rw-r--r--tests/sh.testcases29
3 files changed, 61 insertions, 28 deletions
diff --git a/hush.c b/hush.c
index 126f9da89..3b1e53c82 100644
--- a/hush.c
+++ b/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/shell/hush.c b/shell/hush.c
index 126f9da89..3b1e53c82 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 88e709f87..e2a75873e 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