Motivation
During the vacation, I read the Linuxuser magazine copy from March 2018, I got from Grazer Linuxtage 2018. It mainly concerns shells and mentions some of them. I am unsatisfied with my current zsh setup, so I wanted to discover alternatives. I booted a current xubuntu 20.04 from USB stick and installed the shells to test them. I failed to identify criteria to compare them, but I made notes for each of them. So consider this as an unstructured like. The summary should be somehow helpful though.
Besides those introductory articles, I used awesome-shell and this curated list to get a list of software to review.
Fundamentally, POSIX' string-based argv was certainly appropriate in the 80s, but these days it fundamentally limits the way to pass arguments to CLI tools. On a basic level, each program needs to parse the given array of string into an associative array of key-value pairs where a type mismatch needs to return proper error messages. Hence, each programming language features 20 different CLI parsing APIs with varying degree of quality. In a POSIX shell, everything is considered as byte sequence. A pipe uses the newline character to split byte sequences. These days, I am not the only one missing proper data types, type checking, syntax highlighting and improved visualizations for command output like in general programming languages.
Before this review, I used the zsh in combination with grml’s config. De facto, I use about 0.5% of the features and cannot tell which parts are contributed by grml and which parts are contributed by zsh. I am not a big fan of studying DSLs (domain-specific languages) for every task. After this review I recognized that I barely use any features of the grml config. Helpful features for me are history search via Ctrl+r, hashes and functions.
Comparison notes
shell | remarks |
---|---|
bash |
advanced korn shell (ksh) |
busybox |
minimalistic shell |
dash |
minimalistic shell, provided as /bin/sh in debian |
elvish |
interactive shell, syntax highlighting, DSL, pipe semantics extended for structured data, awesome navigator mode, Ctrl+R history lookup, prefix notation arithmetical operations, functional immutable data structures, well-thought through, implemented in Go |
esh |
minimalistic LISP-based shell |
fish |
interactive shell with syntax highlighting, tab completion for file & folder paths, syntax is POSIX-inspired but simpler, w/o Ctrl+R for history search, filepath is cd-per-default, unicode characters via \uXXXX, with Cartesian products for lists and proper range syntax for lists |
ion |
rust-based simplified syntax, tab completion for files/dirs broken in xfce4-terminal, neat brace expansion, useful ranges, suugestions by history, Ctrl+R history search, rust-like match statement, custom but POSIX-like redirections, optional type checking for functions |
ksh93 |
shell giving the basis of POSIX |
mksh |
POSIX-like shell used by OpenBSD |
nushell |
shell with great representation skills for tabular data, syntax highlighting, auto suggestions for commands and filesystem paths, no tab selection, rust style error messages, no functions, no variables, implemented in rust |
oksh |
portable OpenBSD ksh, based on pdksh |
osh |
awkward POSIX-shell extensions with shitty documentation |
posh |
featureless shell with 9 custom builtin commands |
pdksh |
public domain implementation of korn shell |
shell++ |
OOP shell with large C++ code stack to build, custom glob patterns, python/Go/Javascript-inspired syntax and functions, no tab-completion, broken documentation examples (' used but " required), lacks string representation for various types |
tcsh |
“C shell with file name completion and command line editing”, 12-step compilation instructions requiring adjustments for Ubuntu 20.04, stopped to look into compilation, feature-less POSIX-alternative shell |
xonsh |
very advanced python-based shell with autocompletion, pipes, I/O redirection, color syntax support, Ctrl+R history search |
yash |
Neat POSIX-compatible shell with many builtin functions and syntax highlighting, Ctrl+R search, tab completion for CLI arguments |
zsh (ohmyzsh) |
advanced DSL on top of POSIX shell, rjk & linuxonly & trapd00r themes are okay |
So, what is my conclusion? Which shell shall I pick?
-
Do you need a POSIX shell or want a shell with few main memory requirements?
elvish examples
Technically I think, xonsh is best used for my work [cryptography research] (easy data manipulation with python), elvish is an interesting try and yash is best for my server systems. In short, I am going to try elvish. First of all, I had to migrate my zsh configuration to elvish. Here are some examples to give you an idea of elvish:
mem() { ps -eo rss,pid,euser,args:100 --sort %mem | grep -v grep | grep -i $@ | awk '{printf $1/1024 "MB"; $1=""; print }' } # zsh
fn mem [@p]{ e:ps -eo rss,pid,euser,args:100 --sort %mem | grep -v grep | grep -i "$@p" | awk '{printf $1/1024 "MB"; $1=""; print }' } # elvish
hash -d X="PATH" # zsh
X = "PATH" # elvish, variable as fallback
export GOROOT="/opt/go/"
set-env GOROOT "/opt/go/"
And here I wrote a function to strip the file extension off a file path.
fn strip-file-extension [fp]{
use str
i = (str:last-index $fp ".")
if (eq $i -1) { put $fp }
else { put $fp[0:$i] }
}
Of course this exists in zsh with just two characters to add, but in elvish we only have string operations and the filepath semantics need to implemented separately. You can look up the details in the quite acceptable elvish documentation.
Outlook
In theory, I look for a shell which uses a strict type system. I was wondering which data types would be interesting to consider when designing a shell. My results (obviously heavily inspired by programming languages):
-
bool
-
integer
-
float
-
UTF-8 strings
-
byte array
-
file path
-
URL
-
file size (convertable to various units)
-
exit code
-
semantic version number
-
n-dimensional table (where n=1 corresponds to a list)
-
set
-
JSON/TOML/CSV/INI/YAML/XML abstraction
Update 2020-09-01: I gave a lightning talk about xonsh at PyGraz.