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 withpushd/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
andwait
builtin functions for async code - List index ranges (
$xs[i..j]
)
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}