diff --git a/tests/sh.test b/tests/sh.test index 45444d33..0cc16b9b 100644 --- a/tests/sh.test +++ b/tests/sh.test @@ -79,6 +79,8 @@ testing 'arg shift' "$SH -c '"'for i in "" 2 1 1 1; do echo $? $1; shift $i; don testing '(subshell)' '$SH -c "(echo hello)"' 'hello\n' '' '' testing 'syntax' '$SH -c "if true; then echo hello | fi" 2>/dev/null || echo x'\ 'x\n' '' '' +testing 'syntax2' '$SH -c "for;i 0" 2>&1 | { grep -qi syntax && echo yes; }' \ + 'yes\n' '' '' # The bash man page is lying when it says $_ starts with an absolute path. ln -s "$(which $SH)" bash diff --git a/toys/pending/sh.c b/toys/pending/sh.c index 7fdec3dd..6090d271 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -3176,6 +3176,9 @@ static int parse_line(char *line, struct sh_pipeline **ppl, } else if (strchr(";|&", *s) && strncmp(s, "&>", 2)) { arg->c--; + // Connecting nonexistent statements is an error + if (!arg->c || !smemcmp(ex, "do\0A", 4)) goto flush; + // treat ; as newline so we don't have to check both elsewhere. if (!strcmp(s, ";")) { arg->v[arg->c] = 0; @@ -3186,16 +3189,12 @@ static int parse_line(char *line, struct sh_pipeline **ppl, // ;; and friends only allowed in case statements } else if (*s == ';') goto flush; - - // Connecting nonexistent statements is an error - if (!arg->c) goto flush; pl->count = -1; continue; // a for/select must have at least one additional argument on same line } else if (ex && !smemcmp(ex, "do\0A", 4)) { - // Sanity check and break the segment if (strncmp(s, "((", 2) && *varend(s)) goto flush; pl->count = -1;