diff --git a/Src/subst.c b/Src/subst.c index 14947ae36..c5c060d56 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1860,6 +1860,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * joining the array into a string (for compatibility with ksh/bash). */ int quoted_array_with_offset = 0; + /* Indicates ${|...;} */ + char *rplyvar = NULL; *s++ = '\0'; /* @@ -1887,8 +1889,53 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, * flags in parentheses, but also one ksh hack. */ if (c == Inbrace) { + /* The command string to be run by ${|...;} */ + char *cmdarg = NULL; + size_t slen = 0; inbrace = 1; s++; + + /* Short-path for the command-running substitution ${|cmd;} + * The command string is extracted and executed, and the + * substitution assigned. There's no (...)-flags processing, + * i.e. no ${|(U)cmd;}, because it looks quite awful and + * also requires a change to the manual description of the + * substitution order. Use ${(U)${|cmd;}} instead, it looks + * cleaner. */ + if (*s == Bar && ((slen = strlen(s) - 1) > 1)) { + char *outbracep = s + slen; + if (outbracep[0] == Outbrace /* && outbracep[-1] == ';' */) { + + if ((rplyvar = itype_end(s+1, INAMESPC, 0))) { + if (*rplyvar == Inbrack && + (rplyvar = parse_subscript(++rplyvar, 1, ']'))) + ++rplyvar; + } + if (rplyvar == s+1 && *rplyvar == Bar) { + /* Is ${||...} a subtitution error or a syntax error? + zerr("bad substitution"); + return NULL; + */ + rplyvar = NULL; + } + if (rplyvar && *rplyvar == Bar) { + cmdarg = dupstrpfx(rplyvar+1, outbracep-rplyvar-1); + rplyvar = dupstrpfx(s+1,rplyvar-s-1); + } else { + cmdarg = dupstrpfx(s+1, outbracep-s-1); + rplyvar = "REPLY"; + } + s = outbracep; + } + } + + if (rplyvar && cmdarg && *cmdarg) { + /* Execute the shell command */ + untokenize(cmdarg); + execstring(cmdarg, 1, 0, "cmdsubst"); + s = dyncat(rplyvar, s); + } + /* * In ksh emulation a leading `!' is a special flag working * sort of like our (k). This is true only for arrays or @@ -2588,8 +2635,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, ((unset(KSHARRAYS) || inbrace) ? 1 : -1)), scanflags)) || (v->pm && (v->pm->node.flags & PM_UNSET)) || - (v->flags & VALFLAG_EMPTY)) - vunset = 1; + (v->flags & VALFLAG_EMPTY)) { + if (!rplyvar) { + vunset = 1; + } + } if (wantt) { /*