[Toybox] Shell Compatibility Reports from Oils - ~800 tests passing
Rob Landley
rob at landley.net
Fri Jun 27 09:05:21 PDT 2025
On 6/26/25 23:33, Andy Chu wrote:
> Hello!
>
> I compared many shells for bash compatibility, including toysh:
>
> https://pages.oils.pub/spec-compat/2025-06-26/renamed-tmp/spec/compat/TOP.html
Ooh, more tests! Hmmm, how would I reproduce that myself here...
https://github.com/oils-for-unix/oils/wiki/Spec-Tests
Not exactly a HOWTO.
> toysh passes 809 tests, out of ~2200:
>
> https://pages.oils.pub/spec-compat/2025-06-26/renamed-tmp/spec/compat/PASSING.html
Currently toysh doesn't even pass its OWN test suite if you enable the
$BROKEN tests, and my sh.txt file has another 400 lines of tests I need
to add to that. (I should break down and add command line editing and
history so I can start on !1 and friends, but if the user interface is
polished people assume the engine is done, and it's very much not yet.)
I'm working on it. :)
> What's the motivation for this? Well, two months ago, I thought that
> toysh and OSH (part of https://oils.pub/ ) were the only projects
> aiming for bash compatibility.
I guarantee you some rust zealot out there is doing a rust
implementation for literally no other reason than to write it in rust.
> But then I learned there are TWO shells in Rust aiming at bash
> compatibility, both started in 2022 - in this thread
> https://news.ycombinator.com/item?id=43908368
Yup, there you go. Two of them.
> So I thought you may be interested in this.
Not really. I've never met a rust developer who had any argument for
rust other than "I hate C" and "writing more C is a SIN you HEATHEN".
Which doesn't explain why to use _that_ language for kernels instead of
instead of go, swift, zig... And that's kernels, why not do userspace in
any of the bytecode languages? (I personally like Lua.)
Bash exists. I'm trying to do a self-contained project so I can get a
minimal system down to 4 packages (compiler, kernel, libc, cmdline) so
you can build something like tinycc+linux+musl+toybox and then build
Linux From Scratch under the result.
http://lists.landley.net/pipermail/toybox-landley.net/2020-July/011898.html
I've been working on that general idea for quite a while. My first go at
it (that got me into busybox development in the first place) replaced 20
packages with busybox:
https://landley.net/aboriginal/old/
And my second attempt I got I got the whole self-bootstrapping system
capable of building Linuxx From Scratch and Beyond Linux From Scratch
under itself down to 7 packages (linux, busybox, uClibc, gcc, binutils,
gmake, bash):
https://landley.net/aboriginal/about.html#design
(From which things like Alpine could build a busybox-based distro you
could do real work in.)
If I'm going to get it down to 4 packages (with no other external
dependencies, not even zlib or ncurses), then such a command line needs
a shell, and if it's going to have a shell then bash is the logical
model for that shell. But note how the logic starts with "toybox needs a
shell" not "there's something wrong with the existing bash".
> A few years ago I transcribed some tests from toybox, so thanks for that:
>
> https://pages.oils.pub/spec-compat/2025-06-26/renamed-tmp/spec/compat/toysh.html
>
> https://pages.oils.pub/spec-compat/2025-06-26/renamed-tmp/spec/compat/toysh-posix.html
You're welcome. Glad you found them useful. :)
> ---
>
> I've contacted the authors of the other shells as well -- there seems
> to be a lot of duplicated effort!
https://xkcd.com/927/
I've personally reimplemented basically the entire Linux command line
TWICE. (When I left busybox I'd written about 1/3 of it.)
Duplicated effort is a FEATURE of Linux, that's why it made open source
development work better than other projects. (I gave a talk on this at
Flourish in 2010, "the prototype and the fan club".)
https://landley.net/talks/flourish-2010.txt
Linux being modular (interchangeable parts available from multiple
sources, like old pre-laptop white box PCs) was the main reason* Linux
beat out BSD. BSD was a big monolith that had userspace in the same SVN
repo as the kernel. So you could mix and match parts in Linux in a way
that BSD strongly resisted. When Linux switched from libc5->libc6 that
was a distro choice. Busybox couldn't have happened under BSD, because
you'd have to fork the kernel in order to replace "cat".
* Well, after about 1995. Before that BSD required a hardware FPU and
Linux didn't so a lot of cheap PC hardware was unable to run BSD during
the big rush when the NSF changed the internet AUP in 1993 to allow
for-profit ISPs. Nobody had a budget for "web server" so they fished old
discarded 386 PCs out of closets to be web servers with Linux+Apache,
giving Linux a critical mass of users. Before that there was about 5
years of the legal uncertainty around AT&T vs BSDi that gave Linux its
first foot in the door. And of course before the internet properly hit
critical mass BSD got harvested for talent to work on proprietary forks
every 5 years (Sun hiring away Bill Joy, Bill Jolitz's work being taken
away from him, Jordan Hubbard getting hired away from FreeBSD to work on
MacOSX) costing it a LOT of momentum, something back in the day GPLv2
did prevent. (But note how that harvesting/forking STOPPED when "my open
source portfolio work is more important than my resume" turned into a
thing around y2k, and it never really applied to Apache which was
non-copyleft licensed all along, because its community was on the
internet rather than usenet and cutting yourself off from that for a job
wasn't the cultural norm. Part of the reason for such huge pushback
against GPLv3 is that even GPLv2 mattered a lot less by that point,
because license aside you'd never convince somebody like Alan Cox to cut
himself off from the community to go work on a proprietary fork. The
internet was not usenet.)
> The author of brush has expressed interest in using these spec tests,
> so I am thinking of turning into something more "cross project"
I'd be happy to have more tests, and we've needed a good test suite.
You'll note that mine has "TEST_HOST=1 make test_sh" where bash passes
all the tests.
That said, "I have _chosen_ not to pass this test" is a thing that comes
up with external test suites, which I never quite know how to handle...
> I would even call it "Bashix" -- a superset of POSIX, that multiple
> shells could agree on -- so that users have a stable and well-defined
> language to write.
You may have seen the long threads on here with Chet Ramey, the bash
maintainer. I've also had discussions about standards with Elliott
Hughes the ANdroid base OS maintainer.
Alas, neither of us wants to maintain a standard because it's a TON of work.
> I've noticed for a long time that there is a LOT of behavior that
> multiple shells agree on, e.g. assignment builtins, other builtins,
> and arrays, that is not in POSIX.
See "why not just use posix for everything" in:
https://landley.net/toybox/roadmap.html#susv5
Posix is weirdly a good standard (or at least good at what it does)
because it tries to be a minimal subset everyone can agree on. Which
means it had holes big enough to drive Windows NT and OS/360 through.
But even then: I did not implement sccs, ed, SUSv4's dd'd ebcdic
conersions... Lots of my commands have "deviations from posix" sections
in the source file's header comment block, because a plan is a frame of
reference to diverge from.
> I'm not sure how much time / motivation various authors have, but it
> would probably be useful to coordinate. e.g. I notice many questions
> about alias on the blog.
Because it's _INSANE_.
> OSH has mostly figured those things out,
Oh so have I now, it was just painful getting there.
And I still have a corner case I don't do right. I am WAY behind editing
and posting my blog, but spoilers for June 21:
$ alias ee='echo ' def='abc xyz ' xyz='abc '
$ ee def xyz
abc xyz abc
That's just ANNOYING. (And no, it's not the recursion guard. The
trailing space to retry thing seems to only apply at the top level AND
it tracks when it's consumed all the input string provided BY the top
level, even when the length of string is modified by further alias
substitutions. I'm performing the string and looping parsing
non-recursively because I'm trying to support nommu with potentially
very limited stack depth, they're probably doing something recursive.)
> although now that I look, it
> doesn't quite match bash, although it is tied for the #2 in terms of
> tests passing:
>
> https://pages.oils.pub/spec-compat/2025-06-26/renamed-tmp/spec/compat/alias.html
>
> (I don't think bash is always right, but often it is.)
I'm usually interested in more tests. And I never claimed 100% bash
conformance: even BASH doesn't have 100% bash conformance. (Half my
arguments with Chet _cause_ version skew, which I see as a bug and he
sees as a feature. I ask him to explain a corner case and he FIXES it,
but then what do I put in the test suite if I want to pass TEST_HOST on
"bash"? Do I have to check bash VERSIONS?)
Why isn't bash CONSISTENT?
$ alias potato='abc\def'
$ potato='abc\def'
$ alias potato
alias potato='abc\def'
$ declare -p potato
declare -- potato="abc\\def"
Pick a quoting style! (And the new universal one is $'blah' but see the
xkcd on standards again...)
> Andy
Rob
More information about the Toybox
mailing list