back to

2022-03-20 - the ax shell proposal

a newer version of this document is available here:

the ax shell v0.1

i love shell programming, but i don't love the languages that are currently out there. sh doesn't have a modern feel and is pretty limited. bash is powerful, but has so many complex rules and gotchas that i still find myself referencing the man page after scripting for almost 10 years. zsh is pretty much the same as bash, but with more features. i've read up on the "nu" shell, while it's very different than existing shells, it introduces complexity in very different ways that i can't agree with. i like the direction the fish shell takes, but i still think a simpler solution can be achieved.

with that said, over the past few weeks i've come up with the basic design for a new shell called "ax". while the design is by no means complete, final or without inconsistencies, i do like the general direction it's taking. this project is something i could see myself working on a year down the road after getting feedback and giving it more thought. the remainder of this article will describe the current design, syntax, and reasonings for the ax shell.

the ax shell

the ax shell (pronounced "axe" or "acks") is an acronym for "[a]nother e[x]cellent [shell]". this shell strives to preserve the unix philosophy, while straying from normal posix shell standards. when i say "unix philosophy", the definition i'm referring to is from doug mcilroy:

"this is the unix philosophy: write programs that do one thing and do it well. write programs to work together. write programs to handle text streams, because that is a universal interface."

a few of the design highlights of the ax shell are:

unix philosophy on wikipedia

posix reference

a note on the null character

unix doesn't allow the null character to be a part of filenames, env var names or values, or command arguments. but the null character can be part of the stdout of a program or a file's content. the ax shell abuses this small detail to it's advantage. the null character is essential in how arrays work in the ax shell. for example, ax environment variables allow the null character in it's value, but when you convert it to an argument or when exported to a subprocess, only the string up to the first null character is sent to the command or subprocess. also, spaces in file names no longer become an issue when using command substitutions if you are using the null character as a delimiter. i don't think i could come up with an elegant i liked for the ax shell if null characters didn't have this interesting guarantee.

anyways, let's continue with the specification.

reserved characters

here is a list of all reserved characters. there is no escaping supported. instead of escaping, you should use one of the many string options.


builtins must always be prepended with a "!". it's easy to tell whether something is an executable or just a builtin with this required prefix. unlike normal commands, builtins can conditionally parse command substitutions. this allows for if and loop constructs to be represented as builtins. there may be more builtins in the future, but the list of builtins cannot be extended by ax shell users.

env vars

the ax shell doesn't distinguish exported variables with local variables. only exported environment variables are supported. here are a few of the environment variables that the ax shell populates for you:


as of now, that's the complete syntax for the ax shell. though the list of builtins is not complete and the syntax is still subject to change, the shell is already very powerful as these examples will show.


some things i can think of right now that still need to be hashed out are:

i need to spend some time today doing something else rather than working on this blogpost now. you can see that even with a basic syntax, a powerful shell can be constructed. email me at if you have questions or feedback about this. i'll start prototyping this shell when i consider the design to be complete, which will probably not be for many months at least.