Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

The big kre zsh bug report



Robert Elz a.k.a. kre (author of NetBSD sh) ran "zsh-5.6.2 --emulate sh" against his NetBSD sh test suite and came up with a laundry list of test failures which he wanted to filter through me. Here are the ones I could reproduce in zsh-5.6.2-test-2 and which seemed like bugs to me.

I've ommitted test failures that clearly represent legit zsh extensions, such as empty command lists, arithmetic expressions in lieu of numeric arguments to builtins, or zsh-specific parameter expansions. At least I don't *think* it is the aim of sh/ksh/bash emulation mode to disable all zsh extensions -- just those that would cause incompatibilities.

_____________________
First, kre noted that things like $(( x )), $(( x+=1 )), and the like don't error out if 'set -u' (-o nounset) is active. I don't think that's technically a bug, because 'set -u' is specified to apply to parameter expansion and not arithmetic expansion. (Note that $(( $x )) contains a parameter expansion and 'set -u' works as expected.)

However, I think having 'set -u' apply to $(( x )) is "obvious" and useful behaviour. Bash, ksh93, dash, FreeBSD sh and NetBSD sh already do it (mksh and yash don't). I can't think of any downside so this behaviour. So perhaps this could be considered a feature request.

All further quoted text below is from kre... (Note his test suite output doesn't quote the '-c' option argument, but the tests are executed as if it were quoted with single quotes.)

Op 07-12-18 om 11:39 schreef Robert Elz:
Next, for something different:

tc-so:Executing command [ zsh --emulate sh -c sleep 1 & P=$!; jobs; wait ]
tc-se:Fail: regexp Running not in stdout
tc-se:[1]  + running    sleep 1

Posix says of the "jobs" command that the status is Running (with a capital R)
not "running" with a lower case 'r'.    (Same with Done, ...)

Confirmed. (Note this applies to the POSIX locale.)
Ref.: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/jobs.html#tag_20_62_10

_____________________
Next:

tc-so:Executing command [ zsh --emulate sh -c for op in + - \* / %
tc-so:            do
tc-so:                echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
tc-so:            done ]
tc-se:Fail: incorrect exit status: 1, expected: 0
tc-se:stdout:
tc-se:11
tc-se:
tc-se:stderr:
tc-se:zsh:3: bad math expression: operator expected at `2 '
tc-se:

I am not sure what happened with that one.   zsh did do...

tc-so:Executing command [ zsh --emulate sh -c echo $(( $( echo 3 ) $( echo + ) $
( echo 4 ) )) ]

correctly, so it can handle expansions inside a $(( )) - perhaps the "${op}"
being quoted confused it, but those quotes are inside $( ) and will not survive
the result of that expansion (they are removed before echo runs), so should
be invisible to the arith code.   They are needed so the '*' is not subject to
filename expansion in the case when op=\*

Yes, I don't think the "${op}" being quoted has anything to do with it. It fails only at the second loop iteration, so with '-' as the operator.

So it doesn't like this:

$ zsh --emulate sh -c 'echo $(( $(echo 9) $(echo -) $(echo 2) ))'
zsh:1: bad math expression: operator expected at `2 '
$ zsh --emulate sh -c 'echo $(( 9 `echo -` 2 ))'
zsh:1: bad math expression: operator expected at `2 '

Whereas these works fine:

$ zsh --emulate sh -c 'echo $(( $(echo 9) - $(echo 2) ))'
7
$ zsh --emulate sh -c 'echo $(( 9 $(echo +) 2 ))'
11
$ zsh --emulate sh -c 'echo $(( 9 $(echo \*) 2 ))'
18
$ zsh --emulate sh -c 'echo $(( 9 `echo /` 2 ))'
4

So yes, that's a bug; the '-' operator is somehow handled differently from the rest.

_____________________
This next one is (smilar to) the one you (Martijn) reported wrt
the NetBSD shell just recently (one of the new tests I added
when I fixed it...)

tc-so:Executing command [ zsh --emulate sh -c . ./h-f3; X=1; set -- ; delim_argv "${X+$@}" ]
tc-se:Fail: stdout does not match expected value
tc-se:--- /tmp/inline.Ph8gBl    2018-12-07 05:42:15.944365210 +0000
tc-se:+++ /tmp/check.JvvNwL/stdout      2018-12-07 05:42:15.944098585 +0000
tc-se:@@ -1 +1 @@
tc-se:-
tc-se:+><
"h-f3" just contains the definition of the delim_argv function, which
is simply...

delim_argv() {
        str=
        for Arg; do
                str="${str:+${str} }>${Arg}<"
        done
        printf '%s\n' "${str}"
}
ie: stick ><  (angle quotes, except in the backwards
order, so they are more obvious) around each arg.

This indicates that zsh is parsing that the same way we did I
think, and not producing nothing when there are no args from
the (enclosed) quoted $@

The output is a diff -u with the first arg ('-' lines in output) being what
was expected (the file with "inline" in its name) and the 2nd arg ('+'
lines in the output) being the output from the command.

Hmm... to make this a little easier to understand and reproduce:

zsh --emulate sh -c 'delim_argv() { str=;
		for Arg do str="${str:+${str} }>${Arg}<"; done;
		printf "%s\n" "${str}"; };
	X=1; set -- ; delim_argv "${X+$@}"'

zsh, bash, dash, ksh93, mksh >= R50e, FreeBSD sh output:
><

yash, mksh <= R50 output nothing.

So the issue is that "${X+$@}" should be removed completely and not leave an empty quoted string if X is set, but there are no positional parameters.

Looks logical to me: in that the ${X+$@} parameter substitution substitutes $@, within quotes, leaving "$@", which is definitely removed completely if there are no positional parameters.

But if this is a bug, it's certainly a widespread one!

_____________________
tc-se:dollar_hash[7]: Test of 'set -- a b c; echo ${\#}' failed.
tc-se:[7] expected exit code 2, got 0
tc-se:[7] Expected messages on stderr, nothing produced
tc-se:[7] Expected output '', received '3' tc-se:[7] Full command: <<set -- a b c; echo ${\#}>>

The \ is not removed before var expansion, ${\#} is not ${#}
and \# is not a valid var name, nor is \ if this is being parsed
as a substring match on ${\} so this should be a syntax error
(at least in sh emulation mode).

There is another test which fails in a similar way for the same
reason ...

tc-se:dollar_hash[8]: Test of 'set -- a b c; echo ${\#:-foo}' failed.

Confirmed. ${\#} or ${\#:-foo} should be syntax errors, but aren't.

Same with other special parameters: ${\?}, ${\!}, etc. and even normal variables: ${\foo}.

_____________________
And something different, but related, perhaps:

tc-se:dollar_hash[48]: Test of 'x=hello; set -- a b c; echo ${#x:-1}' failed.
tc-se:[48] expected exit code 2, got 0
tc-se:[48] Expected messages on stderr, nothing produced
tc-se:[48] Expected output '', received '5'
tc-se:[48] Full command: <<x=hello; set -- a b c; echo ${#x:-1}>>

Combining length and set/not set operators is not defined in sh,
and makes no sense anyway, as ${#x} is always set (it is a number,
0 .. whatever, so cannot be unset or null - if 'x' is unset and -u
is on, there might be an error, but returning the length of $x with
this nonsense syntax is always incorrect).

And more like that one ...

tc-se:dollar_hash[49]: Test of 'x=hello; set -- a b c; echo ${#x-1}' failed.
tc-se:dollar_hash[50]: Test of 'x=hello; set -- a b c; echo ${#x:+1}' failed.
tc-se:dollar_hash[51]: Test of 'x=hello; set -- a b c; echo ${#x+1}' failed.
tc-se:dollar_hash[52]: Test of 'x=hello; set -- a b c; echo ${#x+1}' failed.
tc-se:dollar_hash[53]: Test of 'x=hello; set -- a b c; echo ${#x:?msg}' failed.
tc-se:dollar_hash[54]: Test of 'x=hello; set -- a b c; echo ${#x?msg}' failed.
tc-se:dollar_hash[55]: Test of 'x=hello; set -- a b c; echo ${#x:=val}' failed.
tc-se:dollar_hash[56]: Test of 'x=hello; set -- a b c; echo ${#x=val}' failed.
tc-se:dollar_hash[57]: Test of 'x=hello; set -- a b c; echo ${#x#h}' failed.
tc-se:dollar_hash[58]: Test of 'x=hello; set -- a b c; echo ${#x#*l}' failed.
tc-se:dollar_hash[59]: Test of 'x=hello; set -- a b c; echo ${#x##*l}' failed.
tc-se:dollar_hash[60]: Test of 'x=hello; set -- a b c; echo ${#x%o}' failed.
tc-se:dollar_hash[61]: Test of 'x=hello; set -- a b c; echo ${#x%l*}' failed.
tc-se:dollar_hash[62]: Test of 'x=hello; set -- a b c; echo ${#x%%l*}' failed.

I'll leave this for the zsh developers to consider, but personally I think we can legitimately consider this an artefact of a zsh extension.

Zsh has always allowed combining things in parameter substitutions that other shells don't, and allowing nonsensical combinations is simply a side effect of allowing other, sensible ones. Zsh accepting something other POSIX shells don't, even in emulation mode, will not cause any compatibility problems as long as POSIX syntax is followed.

As far as I know, no shell except yash aims to prohibit everything not allowed by POSIX in its POSIX compatibility mode. (IOW, for a strict POSIX compatibility test, I'd highly recommend 'yash -o posix'!)

_____________________
Next we get similar tests, but this time we are testing $# rather than the
length of a var operator...

tc-se:dollar_hash[79]: Test of 'set -- a b c; echo ${#:-99}' failed.
tc-se:[79] Expected output '3', received '2'
tc-se:[79] Full command: <<set -- a b c; echo ${#:-99}>>

For $# I am not sure posix requires handling the tests for set/unset
(as $# is always set) so I would understand an error here, but not
the wrong answer, there are 3 args $# should be 3, it is never unset
or null, so the :-99 part should just be noise (or an error).

Confirmed:

$ zsh --emulate sh -c 'set -- a b c; echo ${#:-99}'
2

That should be 3, so this is a bug.

Hmmm...

$ zsh --emulate sh -c 'set -- a b c; echo ${#}'
3
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-}'
0
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-3}'
1
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-3000}'
4
$ zsh --emulate sh -c 'set -- a b c; echo ${#:-10chstring}'
10
$ zsh --emulate sh -c 'bar=10chstring; set -- a b c; echo ${#:-$bar}'
10

So what happens is that ${#:-foo} measures the length of whatever follows ':-'. Interesting behaviour, but not correct, at least not for POSIX mode.

_____________________
This next one does generate an error from zsh, which is not
unreasonable:

tc-se:dollar_hash[80]: Test of 'set -- a b c; echo ${#-99}' failed.
tc-se:[80] expected exit code 0, got 1
tc-se:[80] Messages produced on stderr unexpected...
tc-se:zsh:1: bad substitution
tc-se:[80] Expected output '3', received ''
tc-se:[80] Full command: <<set -- a b c; echo ${#-99}>>

so why it acted differently when the ':' was there is hard to explain.

I think it's a (minor) bug. Since $# is always set, ${#-foo} should be accepted as equivalent to $#.

I see them same (not really incorrect, this is in "unspecified" territory
I think ... our tests test NetBSD sh behaviour)...

tc-se:dollar_hash[84]: Test of 'set -- a b c; echo ${#?bogus}' failed.
tc-se:[84] expected exit code 0, got 1
tc-se:[84] Messages produced on stderr unexpected...
tc-se:zsh:1: bad substitution
tc-se:[84] Expected output '3', received ''
tc-se:[84] Full command: <<set -- a b c; echo ${#?bogus}>>

IMHO, same as above: $# is always set, so ${#?bogus} should be accepted as equivalent to $#.

_____________________
This next one is an obvious, and common, problem ...

tc-se:shell_params[13]: Test of 'set -- a b c d; echo ${4294967297}' failed.
tc-se:[13] Expected output '', received 'a'
tc-se:[13] Full command: <<set -- a b c d; echo ${4294967297}>>

(4294967297 & 0xFFFFFFFF) == 1

This indicates that 32 bit arith overflow occurred, and wasn't detected.

Confirmed (also on ksh93 and dash).

_____________________
This next one indicates that \newline line joining is not working correctly
I think ...

tc-so:Executing command [ zsh --emulate sh -c line='#define bindir "/usr/bin" /* comment */'; echo :"$\
tc-so:{li\
tc-so:ne%\
tc-so:'/*'*}": ] tc-se:Fail: stdout does not match expected value
tc-se:--- /tmp/inline.FL7wVx    2018-12-07 05:42:17.365040418 +0000
tc-se:+++ /tmp/check.5PcEmx/stdout      2018-12-07 05:42:17.364785460 +0000
tc-se:@@ -1 +1 @@
tc-se:-:#define bindir "/usr/bin" :
tc-se:+:{line%'/*'*}:
Since the previous test ...

tc-so:Executing command [ zsh --emulate sh -c line='#define bindir "/usr/bin" /* comment */'; echo :${line\
tc-so:%\
tc-so:'/*'*}: ]
does work, and it should end up being the exact same thing, my guess is
that the ${ with a \newline between the $ and { is not working as it should.

Confirmed. A bit more experimenting shows that it breaks between '$' and '{' and nowhere else. Very unlikely for line continuation to be used there in real-life scripts, but still a bug.

$ zsh --emulate sh -c 'foo=bar; echo $\
foo'
bar
$ zsh --emulate sh -c 'foo=bar; echo $\
{foo}'
{foo}
$ zsh -c 'line='\''#define bindir "/usr/bin" /* comment */'\''; echo :"${\
l\
i\
n\
e\
%\
'\''\
/\
*\
'\''\
*\
}\
"\
:'
:#define bindir "/usr/bin" :

_____________________
Next ...

	check 't=" x";     IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1'

The first arg to "check" is evaluated using ${SHELL} -c the 2nd arg is the
expected output.... This one is test 2 of the IFS tests (test 1 passed).

tc-end: 1544161337.630429, ifs, failed, Test 2 't=" x";     ...': expected [1], found [2 :]

(unfortunately here, when it fails, the "check" in question truncates the
command in the message, it is expected you will look at the test source
to see what it really was.... so I am including the ones that fail.   I should
improve the output from this "check" function - this was an early version...

The data enclosed in [] is what should have been output. and what
actually was.

I think this means that zsh is not treating non-whitespace IFS characters
as field terminators, but as field separators, which is not the way it is
supposed to be.  A later failure is because of the same thing I believe.

Confirmed. Modernish identifies this as a shell quirk (QRK_IFSFINAL) because the POSIX spec is quite ambiguous on this, so I was unable to confirm that it is actually a bug and not a legitimate behaviour variant.

However, yash's author, magicant, has since decided it's a bug, and fixed it, adding a shell option to restore the old behaviour. See discussion here:
https://osdn.net/projects/yash/ticket/35283

He refers to this clarification:
http://www.open-std.org/JTC1/SC22/WG15/docs/rr/9945-2/9945-2-98.html

So this should probably be fixed, at least for sh emulation mode.

_____________________
Next, with IFS containing a digit...

        check 'IFS=5; echo $(( 123456789 ))'    '1234 6789'

tc-end: 1544161337.819973, split_arith, failed, Test 1 'IFS=5; echo ...': expect
ed [1234 6789], found [123456789]

This has come up before on zsh-workers. It's known that artihmetic expansion is not subject to field splitting in zsh and they've declined to fix it on the grounds that field splitting arithmetic expansions is nonsensical. I would prefer consistent field splitting of all dollar expansions as the standard requires, but was outgunned by Stéphane Chazelas. (IMHO, a more sensible use case would be to split on the decimal point.)

_____________________
The next test is also perhaps dubious, and bizarre, but ...

        check 'cat <<  echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" 'echo' 0

($nl is a single newline character).

tc-se:lineends[2]: test of 'cat <<  echo
tc-se:\
tc-se:echo
tc-se:echo
tc-se:' failed

The point here is that the here doc delimiter
is unqoted "echo", then in the here doc, the \
on the first line joins the 2nd line to it, which
as I read the spec, means it cannot be the
terminator of the here doc, no matter what it
ends up containing, as that is required to be
on a line containing nothing else (after leading
tabs are stripped if appropriate, which isn't the
case here, and there aren't any anyway).  If
a line has been joined to a previous line, I interpret
that as meaning it cannot be the terminator (and
allowing it to be adds nothing useful to the shell,
other than the potential for errors).

Hence, I believe in this that "echo" is the correct
output.    But if the first "echo" terminates, we get
no output (as trailing newlines get removed by
the command substitution that "check" uses to
capture the results, so the missing \n from the
echo command that would follow makes sense).

But this is a view of how here docs work that is
not necessarily agreed by all...

Your interpretation looks correct to me, but few real-life shells follow it (dash, recent yash, and ksh93 are the ones I can quickly identify).

_____________________
Next, zsh apparently does not implement the posix
required -h option.   Nor do we, but we at least allow
it to be set and cleared ....

I'm not sure that allowing it to be set and then not doing what it promises is better than not allowing it to be set at all.

_____________________
Next onto pattern tests ...

tc-se:case_matching[51]: Test of 'case "[a-c]" in ([a-c\]) printf M;; (*) printf X;; esac' failed.
tc-se:[51] Messages produced on stderr unexpected...
tc-se:zsh:1: bad pattern: [a-c]
tc-se:[51] Expected output 'M', received ''
tc-se:[51] Full command: <<case "[a-c]" in ([a-c\]) printf M;; (*) printf X;; esac>>

There is no such thing as a "bad pattern" in sh - there is no
[xyz] expression there, because of the quoted ']' (so there is
no terminator) which means the '[' is just a character, so this
pattern is effectively just "[a-c]" which should match the word
which is the same thing.

It works when the [ is quoted ( \[a-c] ), or when the whole thing is ( "[a-c]" ).

[...and, moved up here from later in the original email...]
tc-se:var_substring_matching[94]: Test of 'var='[a-c]d-f';printf '%s\n' ${var#[a-c\]}' failed.
tc-se:[94] expected exit code 0, got 1
tc-se:[94] Messages produced on stderr unexpected...
tc-se:zsh:1: bad pattern: [a-c]
tc-se:[94] Expected output 'd-f', received ''
tc-se:[94] Full command: <<var='[a-c]d-f';printf '%s\n' ${var#[a-c\]}>>

This is the same issue as the earlier 'case' matching problem.
There are no bad patterns in sh.   Ever.   The literal string
'[a-c]' should be removed from the start of the value of var.

Properly quoted test cases:

$ zsh --emulate sh -c 'case "[a-c]" in ([a-c\]) printf M;;
	(*) printf X;; esac'
$ zsh --emulate sh -c "var='[a-c]d-f';printf '%s\\n' \${var#[a-c\\]}"

Confirmed. The first test case works on all shells except zsh. For the second, it works on all except zsh, ksh93 and mksh; the latter two don't throw an error, but fail to remove the '[a-c]'.

_____________________
tc-se:case_matching[90]: Test of 'case a in ([[\:alpha:]]) printf M;; (*) printf X;; esac' failed.
tc-se:[90] Expected output 'X', received 'M'
tc-se:[90] Full command: <<case a in ([[\:alpha:]]) printf M;; (*) printf X;; esac>>

Here the quoted ':' means there is no char-class, so what is
left is a simple [xyz] expression, where the xyz part is "[\:alpha:"
the following ']' terminates that expression, and the ']' that
follows it is just a character.   The 'a' matches the [...] (which
contains an 'a') but there is nothing in the word to match that
extra ']', so the match should fail.

tc-se:case_matching[96]: Test of 'var=":alpha:"; case B in ([["$var"]]) printf M;; (*) printf X;; esac' failed.
tc-se:[96] Expected output 'X', received 'M'
tc-se:[96] Full command: <<var=":alpha:"; case B in ([["$var"]]) printf M;; (*) printf X;; esac>>

This is similar. the : is quoted (via quoted $var) so there is no
char class, just a [] expression followed by a stray ']'

tc-se:case_matching[98]: Test of 'var=":alpha:"; case "[]" in ([["$var"]]) printf M;; (*) printf X;; esac' failed.
tc-se:[98] Expected output 'M', received 'X'
tc-se:[98] Full command: <<var=":alpha:"; case "[]" in ([["$var"]]) printf M;; (*) printf X;; esac>>

This is the same thing, buit in a "should match" scenario, the [
in the word is matched by the [xyz] expression, which contains a '['
(for the same reason as the last two) and the ] in the word matches
the trailing ] that comes after the [xyz] expression, and we have a match.

Yes, that looks like three ways of testing the same thing.

Shells differ here. bash, dash, mksh<=R55 print X on the first and second, M on the third; yash, ksh93, mksh>=R56c, zsh print M on the first and second, X on the third.

_____________________
tc-se:case_matching[147]: Test of 'var='\z'; case ${var} in (${var}) printf M;; (*) printf X;; esac' failed.
tc-se:[147] Expected output 'X', received 'M'
tc-se:[147] Full command: <<var='\z'; case ${var} in (${var}) printf M;; (*) printf X;; esac>>

The word to match is two chars, backslash and z, the pattern is
a quoted 'z' (the backslash becomes a quoting character).   After
that happens, there is nothing magic in the pattern, just one literal
char, 2 chars can never match 1, so it should fail.

Properly quoted test case:

$ zsh --emulate sh -c 'var='\''\z'\'';
	case ${var} in (${var}) printf M;; (*) printf X;; esac'

This outputs X on bash, dash, ksh93, and M on yash, mksh, zsh.

This issue caused me headaches when implementing match() on modernish. I was given the impression that passing backslash-quoted characters through variables for use in 'case' patterns was one of those things that POSIX doesn't really specify one way or another. Of course I would much prefer the behaviour of bash, dash, and NetBSD sh.

_____________________
tc-se:case_matching[265]: Test of 'var='\'; case '\' in ($var) printf M;; (*) printf X;; esac' failed.
tc-se:[265] Expected output 'X', received 'M'
tc-se:[265] Full command: <<var='\'; case '\' in ($var) printf M;; (*) printf X;; esac>>

This one is excusable, a \ followed by nothing in a pattern is an unspecified
case, so anything is OK, and treating it as a literal \ is reasonable (it is
just not what we do ... it is also not what bash does, so as this one also fails in bash emulation, there probably is something that needs fixing.

tc-se:case_matching[267]: Test of 'set -- \\ \\; case $1 in ($2) printf M;; (*) printf X;; esac' failed.
tc-se:[267] Expected output 'X', received 'M'
tc-se:[267] Full command: <<set -- \\ \\; case $1 in ($2) printf M;; (*) printf X;; esac>>

This one is the same, both pattern and word are '\'  just created
in a different way.

tc-se:case_matching[271]: Test of 'case '\' in ($( echo '\' )) printf M;; (*) printf X;; esac' failed.
tc-se:[271] Expected output 'X', received 'M'
tc-se:[271] Full command: <<case '\' in ($( echo '\' )) printf M;; (*) printf X;; esac>>

That one too.   Note all 3 of them work the same in bash as we expect,
and all 3 still fail with zsh --emulate bash

I'm not sure the zsh authors aim to make emulation modes quite that exact, but I'll just leave this here for their consideration.

_____________________
tc-se:var_substring_matching[47]: Test of 'var='abc';printf '%s\n' ${var%*}' failed.
tc-se:[47] Expected output 'abc', received 'ab'
tc-se:[47] Full command: <<var='abc';printf '%s\n' ${var%*}>>

This one is easy, * should start out matching nothing, that matches, so
nothing should be removed from the value.   zsh is removing 'c'.
(Yes, it is a stupid thing to do, or to expect to work, but it is how it
is supposed to function.)

tc-se:var_substring_matching[48]: Test of 'var='abc';printf '%s\n' "${var%*}"' failed.
tc-se:[48] Expected output 'abc', received 'ab'
tc-se:[48] Full command: <<var='abc';printf '%s\n' "${var%*}">>

That is the same, just in a quoted expansion (should change nothing).

Properly quoted test cases:

$ zsh --emulate sh -c "var='abc';printf '%s\\n' \${var%*}"
$ zsh --emulate sh -c "var='abc';printf '%s\\n' \"\${var%*}\""

Bug confirmed; every shell except zsh prints 'abc'.

_____________________
Various other tests showed that zsh cannot handle file descriptors >9. Not really a bug as POSIX permits that limitation, but:

And again, this test fails the same way with --emulate bash
and bash certainly permits fds > 9!

So you could consider this a feature request.

_____________________
tc-so:Executing command [ zsh --emulate sh -c  set -- a b c d; shift 1 1 ; echo FAILED  ]
tc-se:Fail: incorrect exit status: 0, expected: anything else
tc-se:stdout:
tc-se:FAILED
tc-se:
tc-se:stderr:
tc-se:

shift should only take 1 arg, not two ... but most shells do not check that,
so this one is perhaps excusable.

I think builtins should always fail on excess arguments since, outside of test cases, that is a clear indication something has gone awry in the script.

_____________________
In this one zsh is generating a syntax error, when there is none...

tc-so:Executing command [ zsh --emulate sh -c echo hello; true&false&:&cat</dev/null>/dev/null&x=3& echo world ]
tc-se:Fail: incorrect exit status: 1, expected: 0
tc-se:stdout:
tc-se:
tc-se:stderr:
tc-se:zsh:1: parse error near `&'
tc-se:

Which of the numerous '&' chars it does not like I have no idea.

Looks like zsh doesn't like a bare shell assignment as a background job.

$ zsh --emulate sh -c 'x=3 &'
zsh:1: parse error near `&'

Pointless or not, this is a bug. All other shells accept this.

_____________________
tc-so:Executing command [ zsh --emulate sh -c case in in (esac|cat ]
tc-se:Fail: incorrect exit status: 0, expected: anything else
tc-se:stdout:
tc-se:
tc-se:stderr:
tc-se:

I cannot even begin to imagine what that nonsense parsed as...
(but once a case pattern is started with the optional '(' it requires
the following ')' to complete it, always.

Probably related to zsh accepting empty command lists in all sorts of contexts where other shells don't. But it still seems strange that it accepts this:

$ zsh --emulate sh -c 'case in in (esac'
(no syntax error produced)

_____________________
And another one that zsh cannot parse, though again, this one
is legal...

tc-so:Executing command [ zsh --emulate sh -c if if :;then :;fi then :;fi ]
tc-se:Fail: incorrect exit status: 1, expected: 0
tc-se:stdout:
tc-se:
tc-se:stderr:
tc-se:zsh:1: parse error near `then'
tc-se:

I would guess it is the second "then" that follows "fi" with no ';'
that is the problem, but that is OK syntax.

I would not have thought that to be correct syntax, but sure enough, every shell except zsh accepts it.

A similar case (with another reserved word, 'esac', directly preceding 'then') works fine:

$ zsh --emulate sh -c 'if case a in a) ;; esac then :; fi'
(no syntax error produced)

However, this one fails on zsh and works on all other shells:

$ zsh --emulate sh -c 'if until :; do :; done then :; fi'
zsh:1: parse error near `then'

_____________________
tc-so:Executing command [ zsh --emulate sh -c case x in (|| | ||) ;; esac ]
tc-se:Fail: incorrect exit status: 0, expected: anything else
tc-se:stdout:
tc-se:
tc-se:stderr:
tc-se:

Not sure what I should say about that one... (but patterns are not
allowed to be completely missing, there must be a word, and lots
of alternative illegal missing patterns does not make it legal).

This was a syntax error in zsh until 5.4.1; 5.4.2 starts accepting it.

Strangely, dash accepts this.

_____________________
There is a failure of a test testing %n notation for jobs in wait commands,
but I need to check that one more carefully before complaining about it
failing, it may be that the test is technically invalid (ie: that zsh is
permitted to act as it does) but this next one ...

tc-so:Executing command [ zsh --emulate sh -c wait 1 ]
tc-se:Fail: incorrect exit status: 1, expected: 127
tc-se:stdout:
tc-se:
tc-se:stderr:
tc-se:zsh:wait:1: pid 1 is not a child of this shell
tc-se:

is clearly wrong.  The error message is maybe OK (it is
correct, though I don't think "wait" is supposed to issue it)
but the exit status is clearly wrong, wait is required to return
status 127 when the given pid is not a child, not 1.

Bug confirmed:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/wait.html#tag_20_153_14

ksh93 returns status 0, which is even more wrong! All other shells except zsh return status 127.

_____________________

That's it. Hope this is useful!

- M.



Messages sorted by: Reverse Date, Date, Thread, Author