diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 183ca6e03..b77942697 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1950,6 +1950,9 @@ the braces by whitespace, like `tt(${ )...tt( })', is replaced by its standard output. Like `tt(${|)...tt(})' and unlike `tt($LPAR())...tt(RPAR())', the command executes in the current shell context with function local behaviors and does not create a subshell. +Word splitting does not apply unless tt(SH_WORD_SPLIT) is set, but +trailing newlines em(are) stripped unless the substitution is enclosed +in double quotes. Note that because the `tt(${|)...tt(})' and `tt(${ )...tt( })' forms must be parsed at once as both string tokens and commands, all other diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index 4a86050e6..0515d2fca 100644 --- a/Etc/FAQ.yo +++ b/Etc/FAQ.yo @@ -1092,10 +1092,11 @@ sect(Comparisons of forking and non-forking command substitution) affects the caller. mytt($(command)) removes trailing newlines from the output of mytt(command) - when substituting, whereas mytt(${ command }) and its variants do not. - The latter is consistent with mytt(${|...}) from mksh but differs from - bash and ksh, so in emulation modes, newlines are stripped from command - output (not from tt(REPLY) assignments). + when substituting, as does mytt(${ command }) when not quoted. Placing + double quotes around mytt("${ command }"), or using either mytt(${|...}) + format, retains newlines. The latter is consistent with mytt(${|...}) + from mksh, but mytt("${ command }") differs from bash and ksh, so in + emulation modes, newlines stripped even from quoted command output. When not enclosed in double quotes, the expansion of mytt($(command)) is split on tt(IFS) into an array of words. In contrast, and unlike both diff --git a/Src/subst.c b/Src/subst.c index 49f7336bb..785137357 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2005,7 +2005,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, int onoerrs = noerrs, rplylen; noerrs = 2; rplylen = zstuff(&cmdarg, rplytmp); - if (! EMULATION(EMULATE_ZSH)) { + if (! EMULATION(EMULATE_ZSH) || !qt) { /* bash and ksh strip trailing newlines here */ while (rplylen > 0 && cmdarg[rplylen-1] == '\n') rplylen--; diff --git a/Test/D10nofork.ztst b/Test/D10nofork.ztst index d6a5588df..1c6a30cb0 100644 --- a/Test/D10nofork.ztst +++ b/Test/D10nofork.ztst @@ -159,7 +159,7 @@ F:Why not use this error in the previous case as well? 1:unbalanced braces, part 4+ ?(eval):1: closing brace expected - purr ${ purr STDOUT } + purr "${ purr STDOUT }" 0:capture stdout >STDOUT > @@ -322,7 +322,7 @@ F:Fiddly here to get EOF past the test syntax 0:here-string behavior >in a here string - <<<${ purr $'stdout as a here string' } + <<<"${ purr $'stdout as a here string' }" 0:another capture stdout >stdout as a here string > @@ -331,7 +331,7 @@ F:Fiddly here to get EOF past the test syntax wrap=${ purr "capture in environment assignment" } typeset -p wrap 0:assignment context >typeset -g wrap='REPLY in environment assignment' ->typeset -g wrap=$'capture in environment assignment\n' +>typeset -g wrap='capture in environment assignment' # Repeat return and exit tests with stdout capture @@ -410,7 +410,7 @@ F:must do this before evaluating the next test block 0:ignored braces, part 1 >buried} - purr ${ purr ${REPLY:-buried}}} + purr "${ purr ${REPLY:-buried}}}" 0:ignored braces, part 2 >buried >} @@ -418,7 +418,6 @@ F:must do this before evaluating the next test block purr ${ { echo nested ;} } 0:ignored braces, part 3 >nested -> purr ${ { echo nested } } DONE 1:ignored braces, part 4