• Stars
    star
    379
  • Rank 113,004 (Top 3 %)
  • Language Tcl
  • Created almost 8 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Guidance for mollusks (WIP)

All the broken
Too many broken
Shells
In our shellmounds
β€” Grayceon, Shellmounds

Build Your Own Shell

This is the material for a series of workshops I ran at my workplace on how to write a Unix shell.

The focus is slightly more on building an interactive shell than a scripting-oriented shell, only because I think this is more gratifying, even if it's less useful.

Be warned that some of the suggestions and discussion make opinionated choices without discussing equally-valid alternatives.

This is a work in progress and there may remain many infelicities. Patches Thoughtfully Considered. Feel free to report issues via Github.

Why write your own shell?

The shell is at the heart of Unix. It's the glue that makes all the little Unix tools work together so well. Understanding it sheds light on many of Unix's important ideas, and writing our own is the best path to that understanding.

This workshop has three goals:

  • to give you a better understanding of how Unix processes work;
    • this will make you better at designing and understanding software that runs on Unix;
  • to clarify some common misunderstandings of POSIX shells;
    • this will make you more effective at using and scripting ubiquitous shells like bash;
  • to help you build a working implementation of a shell you can be excited about working on.
    • there are endless personal customizations you can make to your own shell, and can help you think about how you interact with your computer and how it might be different.

(some of this rationale is expanded on in my blog post, Building shells with a grain of salt)

How to use this repository

I've tried to break this up into progressive stages that cover mostly orthogonal topics. Each stage contains a description of the facilities that will be discussed, a list of manpages to consult, and a set of tests. I've tried to also hint at some functionality that is fun but not necessary for the tests to pass.

In the root of this repository, there is a script called validate; you can run all the tests against your shell-in-progress by specifying the path to your shell's executable, like this:

$ ./validate ../mysh/mysh

It should tell you what stage you need to implement next.

To run the tests, you will need expect, which is usually in a package called expect, and a C compiler. The way the tests are implemented is less robust than one might hope, but should suffice for our pedagogical goals.

The tests assume you will be implementing a vanilla Bourne-flavored shell with some ksh influences. Feel free to experiment with alternate syntax, but if so, you may need to adjust the tests. Except where specifically noted, bash (and ksh) should pass all the tests, so you can "test the tests" that way. (Try ./validate /bin/bash; likewise, cat should fail all the tests. Originally, I targeted plain /bin/sh, but I decided the material in stage 5 was too important.)

Stages

1: fork/exec/wait

In which we discuss the basics of Unix processes, write the simplest possible shell, and then lay the foundations for the rest of the steps.

2: files and pipes

In which we add pipes and fd redirection to our shell.

3: job control and signals

In which we discuss signals and add support for ever-helpful chords like ^C, ^\, and ^Z.

4: quoting and expansion

In which we discuss environments, variables, globbing, and other oft-misunderstood concepts of the shell.

5: interactivity

In which we apply some polish to our shell to make it usable for interactive work.

&: where to go next

In which I prompt you to go further.

Shells written from this workshop

I'll link to some of the shells that were written as a result of this workshop here shortly, including a couple I wrote to serve as examples of different approaches.

Supplementary Material

Documents

Other Tutorials

I wrote this workshop partially because I felt other tutorials don't go far enough, but all of these are worth reading, especially if you're having trouble with a stage they cover:

References

Shells to Examine

  • busybox: C; contains both ash and hush, and test suites.
  • mksh: C; non-interactive tests.
  • rc: C; fairly minimal.
  • zsh: C; extremely maximal.
  • bash: C.
  • fish: C++11; has expect-based interactive tests.
  • Thompson shell: C; the original Unix shell; very minimal.
  • scsh: Scheme and C; intended for scripting.
  • cash: OCaml; based on scsh.
  • eshell: Emacs Lisp.
  • oil: Python and C++; has an extensive test suite.
  • xonsh: Python.
  • oh: Go.

Links to Resources by Language

Although there is an elegant relationship between C and Unix which makes it attractive to write a shell in the former, to minimize frustration I suggest trying a higher-level language first. Ideally the language will have good support for:

  • making POSIX syscalls
  • string manipulation
  • hash tables

Languages that provide a lot of their own infrastructure with regards signals or threads may be much more difficult to use.

C++

http://basepath.com/aup/ex/group__Ux.html

Common Lisp

The most convenient library would be iolib, which you can get through Quicklisp. You'll need to install libfixposix first. There's also sb-posix in sbcl for the daring.

Haskell

Java / JVM-based languages

You will probably run into issues related to the JVM, particularly with signals and forking, but as a starting point, you could do worse than loading libc with JNA.

There's also jtux.

Lua

There are a variety of approaches, but ljsyscall looks promising.

OCaml

See also Unix system programming in OCaml, cash.

perl

See perlfunc(3perl); all the functions we want are at hand, usually with the same name.

Python

Although Python provides higher-level abstractions like subprocess, for the purposes of this workshop you probably want to use the functions in os.

Racket

The implementation seems a little too heavy to do this conveniently, but see the Scheme section below for alternatives.

Ruby

Process has most of what you need. You can use Shellwords but you decide if it's cheating or not.

Rust

Although we use few enough calls that you could just create bindings directly, either to libc with the FFI or by directly making syscalls, for just getting something working, the nix-rust library should provide all the necessary facilities.

Scheme

Guile already has all the calls you need; see the POSIX section of the Guile manual. Another approach would be to use something like Chibi Scheme with bindings to libc calls.

Tcl

Although core Tcl doesn't provide what's necessary, expect probably does. For example, Tcl doesn't have a way to exec, but expect provides overlay to do this.

More Repositories

1

blur-detection

Some implementations of algorithms for blur detection in JPEGs
C
141
star
2

series

unofficial mirror of git://git.code.sf.net/p/series/series (Richard C. Waters' SERIES package for Common Lisp)
Common Lisp
49
star
3

imago

image manipulation library for Common Lisp
Common Lisp
48
star
4

niffy

NIF testing harness
C
32
star
5

fixie-trie

Compact tries for fixed-width keys
Rust
26
star
6

extrospect-beam

Tools for live extrospection of the Erlang BEAM VM β€” WARNING: early alpha
C
23
star
7

tsdl-image

OCaml SDL2_image bindings to go with Tsdl
OCaml
14
star
8

magic-ringbuffer-rs

Attempt at implementing the Magic Ringbuffer in Rust
Rust
11
star
9

tsdl-mixer

SDL2_mixer bindings to go with Tsdl
OCaml
8
star
10

granderl

Fast-and-loose PRNG NIF
C
8
star
11

tsdl-ttf

SDL2_ttf bindings for Ocaml with Tsdl
OCaml
7
star
12

goose-theme

A gray color theme
Emacs Lisp
7
star
13

wacom-serial-iv

Linux driver for old Wacom serial tablets, protocol IV
C
7
star
14

shred-for-satan

MIDI-driven metronome
OCaml
7
star
15

convergence

Personal archaeology: a GBA game in literate assembly
Assembly
6
star
16

m68k-assembler

A simple, mostly-DevPAC-compatible assembler for the Motorola 68k series of proccessors.
Common Lisp
6
star
17

punchy-the-log

Simple demonstration of hole punching for logging
C
4
star
18

tiny-compact-map

Simple compact popcount array map
Rust
4
star
19

dispatch-comparison

Do not use: rhetorical benchmark
Python
4
star
20

ymamoto

A replay routine for the Atari ST, using the YM2149 chip.
Assembly
4
star
21

advent-of-code-2017

Python
4
star
22

mechanizerl

Web testing tool for Erlang modelled after WWW::Mechanize
Erlang
3
star
23

zookicker

#1GAM February backup plan
OCaml
3
star
24

hyper-ballon-struggle

Restoration of weekend GBA game from 2002 for #1GAM
Assembly
3
star
25

st-linker

A very simple linker to use with m68k-assembler. Outputs Atari ST PRG files.
Common Lisp
3
star
26

erl-tcp-metrics

Read Linux kernel TCP metrics from Erlang
C
3
star
27

erl-dirwatch

Simple directory watching for Erlang
C
3
star
28

pink-bliss-theme

Alex Schroeder's Pink Bliss emacs theme updated for emacs24
Emacs Lisp
2
star
29

parsur

Parser combinators library for Ur/Web
Makefile
2
star
30

cl-ftgl

FTGL bindings for Common Lisp
Common Lisp
2
star
31

griffin

An emacs-driven static blog generator
Emacs Lisp
2
star
32

advent-of-code-2016

Suggested name: legendary-octo-carnival
Common Lisp
1
star
33

normalize-iplist

A gem that probably isn't useful to you
C
1
star
34

talk-swl2017-timing-wheels

Slides from Timing Wheels talk at Systems We Love in Minneapolis
TeX
1
star
35

dentata-alpha

Personal archaeology: an early game library (very obsolete)
C
1
star
36

noose

Trivial command-line newsreader
C
1
star
37

fobwart-alpha

Personal archaeology: a networked game (obsolete)
C
1
star
38

evil-zips

Lovingly crafted zip files for testing restricted unzip implementations
1
star
39

dentata-beta

Personal archaeology: an early game library (obsolete)
C
1
star
40

mumble

Mumble is a package for converting text representations of music into data for specific playroutines.
Common Lisp
1
star
41

6502core

Personal archaeology: 6502 assembler and emulator -- do not use
C
1
star
42

lalr-parser-generator

LALR parser generator; generates Common Lisp output.
Common Lisp
1
star
43

urweb

Unofficial mirror of the Ur/Web compiler
Standard ML
1
star
44

strap

Personal archaeology: tool for "unbooting" a machine (obsolete)
Assembly
1
star
45

green-threading-shootout

C
1
star
46

steaghan

Personal archaeology: a tool for steganography (obsolete)
C
1
star
47

til

Today I Learned
1
star