Skip to content
This repository

A Unix shell written in Go

branch: master
README.md

oh

Oh is a Unix shell written in Go. The following commands behave as expected:

date
cat /usr/share/dict/words
who >user.names
who >>user.names
wc <file
echo [a-f]*.c
who | wc
who; date
cc *.c &
mkdir junk && cd junk
cd ..
rm -r junk || echo "rm failed!"

Oh uses the same syntax for code and data. This enables it to be easily extended:

# The short-circuit and operator is defined using the syntax command.
define and: syntax e (: lst) as {
    define r False
    while (not: is-null: car lst) {
        set r: e::eval: car lst
        if (not r): return r
        set lst: cdr lst
    }
    return r
}

Oh is properly tail-recursive and exposes continuations as first-class values:

define label: method () as: return return
define continue: method (label) as: label label

# Print 1 to 100 using the continuation (return) returned by label.
define count: integer 0
define loop: label
if (lt count (integer 100)) {
    set count: add count 1
    write count
    continue loop
}

Oh exposes pipes, which are implicit in other shells, as first-class values:

define p: pipe

spawn {
    # Save code to create a continuation-based while command. 
    define code '(syntax e (condition: body) as {
        define label: method () as: return return
        define continue: method (label) as: label label

        set body: cons 'block body
        define loop: label
        if (not (e::eval condition)): return '()
        e::eval body
        continue loop
    })

    # Now send this code through the pipe.
    p::write @code
}

# Create the new command by evaluating what was sent through the pipe.
define while2: eval: p::read

# Now use the new 'while2' command.
define count: integer 0
while2 (lt count (integer 100)) {
    set count: add count 1
    write count
}

Oh's environments are first-class and form the basis for its prototype-based object system:

# Create a point prototype.
define point: object {
    # Private members are created with the define command.
    define x: integer 0
    define y: integer 0

    # Public members are created with the public command.
    public move: method self (a b) as {
        set self::x: add self::x a
        set self::y: add self::y b
    }

    public show: method self () as {
        echo self::x self::y
    }
}

# Create a new point by cloning the point prototype:
define o: point::clone

To go get oh:

go get github.com/michaelmacinnis/oh

Oh is released under an MIT-style license.

Background

Despite multiple attempts to improve the Unix shell, its essential character has remained largely unchanged. Popular Unix shells have retained the look and feel established by the Bourne shell and so share a strong family resemblance. The most successful shells in this family (bash, ksh, zsh) are backward compatible with the Bourne shell. Unfortunately, this backward compatibility results in shells that are "inconsistent and confusing command languages."[18]

If you squint hard enough, the Unix shell looks very similar to other existing languages. So similar that many have attempted embedding the Unix shell in an existing language. The problem with this approach is that the result is either "an uglier, and confusing, language"[21] or a language that is more cumbersome when used as an interactive shell.[23]

Like es, fish and rc, oh retains the look and feel of the Unix shell but does not aim for strict backward compatibility. Oh makes substantial improvements to the programming language features of the Unix shell by borrowing heavily from the Scheme dialect of Lisp. Rather than attempting to embed a Unix shell in scheme, oh was designed from scratch.

References

Fexprs:

1. Fexprs as the Basis of Lisp Function Application or $vau : The Ultimate Abstraction


First-class Environments:

2. First-class environments. Discuss. ;)


Unix Shells (Bourne Shell Family):

3. The Bourne Shell

4. Bash

5. The Korn Shell

6. Zsh


Unix Shells (C Shell Family):

7. An Introduction to the C shell

8. Tcsh


Unix Shells (Other):

9. Es: A shell with higher-order functions

10. The Fish Shell

11. Rc - The Plan 9 Shell


Alternative Shells:

12. A High-Level Programming and Command Language

13. Chris S. McDonald. fsh - A Functional UNIX Command Interpreter. Software - Practice & Experience 17(10): 685-700, 1987


Embedding the Unix Shell in an Existing Language:

14. L. M. Campbell and M. D. Campbell. An Overview of the Ada Shell. In USENIX Winter: 302-313, 1986

15. esh, the easy shell

16. Hell: A Haskell Shell

17. J. R. Ellis. A Lisp Shell. SIGPLAN Notices, 15(5):24-34, 1980

18. Using ML as a Command Language

19. Zoidberg - A Modular Perl Shell

20. The Perl Shell

21. Pysh: A Python Shell

22. Rush

23. The Scheme Shell


Shell History:

24. Shell History

25. The Thompson Shell

Something went wrong with that request. Please try again.