You identifed an interesting problem...
The problem is missing POSIX compatibility in dash
.
POSIX distincts bewteen a basic POSIX compatibility level for tiny embedded systems and larger systems (like e.g. Linux) that claim UNIX compatibility. In the latter case, the system needs to implement all so called XSI extensions.
An XSI compatible system would need to expand certain backslash escapes in echo
arguments.
bash
can be compiled to behave POSIX/XSI compliant (and this is e.g. done on Solaris and MacOS), but this is not done for the bash
binary on Linux. If bash
is compiled for POSIX/XSI compliance, it correctly handles backslash escapes for echo
arguments and your example code would work with such a bash
binary from Solaris or MacOS, because there is no POSIX/XSI escape sequence in your example code.
Since bash
on Linux is not XSI compliant, it does not expand backlash escapes for echo
arguments at all and this is why your example code works with bash
on Linux as well.
dash
on the other side claims POSIX/XSI compliance and expands backslash escapes for echo
arguments. If dash
did implement POSIX/XSI compliance correctly, your example code did work with dash
as well. This is because your example code does not contain any POSIX/XSI backslash escape sequence.
POSIX/XSI requires echo
to expand:
\0nnn for an octal number that represents the related character
Your example code contains the backslash sequences:
\1 for the first sed subexpression
and
\2 for the second sed subexpression
and this is not part of the POSIX/XSI echo
escape sequences, so the builtin echo
from a POSIX compliant shell is not permitted to expand them. dash
however incorrectly expands \1
and \2
as octal numbers even tough this is forbidden by POSIX. This is why your example code fails with dash
.
I recommend you to make a bug-report against dash
and either wait for a fix, or to replace echo arg
by printf '%s\n' arg
. This works even with dash
because the known bug with the builtin printf
in dash
does not affect your case.
So we can list the POSIX/XSI bugs from dash
as:
does not support multy-byte characters.
expands \nnn
in echo
arguments even though this is forbidden
does not expand \nnn
in printf
arguments even though this is required.
yash
printsif !MOCK_has(\"nvim\"):
, just like Bash. When I run it withdash
I getMOCK_has(\"nvim\"):
- no non-printable characters. What really issh
that you're using? – Arkadiusz Drabczyk Feb 24 '21 at 19:59/bin/sh -> dash
– oligofren Feb 24 '21 at 20:00\1
is unspecified behavior. Dash interprets it, Bash does not. – Quasímodo Feb 24 '21 at 20:01printf
in the actual example script. – oligofren Feb 24 '21 at 20:02sed
. – oligofren Feb 24 '21 at 20:03example.sh
and didsh example.sh
anddash example.sh
I got the[][]MOCK_has(\"nvim"\)"
string both times. Maybe my environment variables make the difference, but I tried setting different LANG settings (it was LANG=C.UTF-8) without any effect (tried en_US.utf8 and POSIX). Full list: https://gist.github.com/fatso83/ede210b548f41d6514dc760c8012f85d – oligofren Feb 24 '21 at 20:17/bin/sh
was essentially limiting any shell this was linked to some POSIX defined minimal behavior when it saw that $0 == "/bin/sh". – oligofren Feb 24 '21 at 20:22xpg_echo
), but it's different from the usual POSIX-compatibilty option, so Bash as/bin/sh
is the same as Bash as/bin/bash
here. (Confused yet?) – ilkkachu Feb 24 '21 at 20:26