/andy

A better yet simple shell

Primary LanguageGoBSD Zero Clause License0BSD

andy — a better yet simple shell

Andy is a shell named after my beloved OOP professor from my first year in university, Andy Zaidman. Andy if you’re reading this, you’re great! It’s just a shame that what you taught me best is why I should never use Java for anything.

The goal of the Andy shell is to provide a more sane experience to the shell as opposed to the highly deficient POSIX shells such as Bash and Zsh, while still remaining simple and small unlike Fish. It draws inspiration from various shells, most notably Rc from the Plan 9 operating system.

This shell is very much a work in progress, don’t expect anything from this for a while. The currently implemented features are:

  • Simple commands (cat foo bar)
  • File reading (<)
  • File writing (>)
  • File appending (>>)
  • File clobbering (>!)
  • Read from /dev/null (<_)
  • Write to /dev/null (>_)
  • Pipelines (cmd1 | … | cmdN)
  • Condition chains (cmd1 && … || cmdN)
  • cd builtin function with pushd/popd behaviour
  • call builtin function
  • echo builtin function
  • true builtin function
  • false builtin function
  • exec builtin function
  • Value lists ((a b …))
  • String concationation (foo'bar'"baz")
  • Cartesian product list concationation ((foo bar).c; (a b)(c d))
  • Compound commands ({ cmd; cmd })
  • If(-else) expressions (if cmd { … } else if cmd { … } else { … })
  • While expressions (while cmd { … })
  • Tilde expansion (echo ~ ~username)
  • Setting- and reading variables (set x foo; set xʹ $x.c; echo $xʹ)
  • Flattening variables ($^var)
  • Get variable length ($#var)
  • Index into variables ($var[1 1 -2 5])
  • Process substitution (​`{…}, <{…}, >{…}, <>{…})
  • Read stdin into array (cmd | read var)
  • Source scripts (eval file…)
  • Define functions with named arguments (func f arg1 … {…})
  • Function-local- and global variables (set -g …; read -g …)
  • Quote arguments using Andy quoting rules (quote …)
  • Raw strings (r#c…c#)
  • exit builtin function
  • Special read-only variables ($cdstack, $pid, $ppid, $status)
  • For-loops with implicit assignment (for … { echo $_ })
  • For-in-loops (for x in … { echo $x })
  • Shorthand process substitution syntax (​`cmd …)
  • Split process substitutions on delimiters (​`(seps){cmd …})
  • umask builtin function
  • type builtin function
  • CLI arguments via $args
  • Default variable expansion value ($(foo:bar))
  • get builtin function
  • ! builtin function
  • Run code at program exit by defining the ‘sigexit’ function
  • Handle signals with by defining a sig* function
  • async and wait builtin functions for async code
  • List index ranges ($xs[i..j])

Example

This is very early days and very likely to change. Also some of it is already outdated.

# Define a function ‘greet’ that takes an argument ‘name’
func greet name {
    echo "Hello $name!"
}

# Multiline pipelines without newline escaping
grep foo /some/path
| sort
| nl

# Conditionals and writing to stderr
if test $# -lt 1 {
    echo "Usage: $0 [-f] pattern [file ...]" >&2
    exit 1
}

# Read and write to and from /dev/null
cat <_
cat >_

# Explicit file clobbering with ‘>!’
echo hello >my-file
echo hello >my-file   # Fails
echo hello >!my-file  # Succeeds

# Pattern match strings, with implicit breaks and explicit fallthroughs
x = 123
switch $x {
case foo bar
    echo '$x is either ‘foo’ or ‘bar’'
case [0-9]*
    echo '$x starts with a number'
    fallthough
case *
    echo 'This is a default case'
}

# Lists
echo (foo bar).c  # Echos ‘foo.c bar.c’
cat (a b)(x y z)  # Reads the files ax, ay, az, bx, by, and bz

# The same
xs = 1 2 3
xs = (1 2 3)
xs = 1 (2 3)

# The same
xs = foo
xs = (foo)

xs = ('foo bar' baz)
cat $xs   # Read the files ‘foo bar’ and ‘baz’
cat $^xs  # Read the file ‘foo bar baz’

# Process substitution
diff <{cmd1} <{cmd2}