Introduction

This book is not complete, so do not expect all chapters to be finished.

wsh is the WebAssembly-based shell, bringing the power of Wasm to the everyday programmer! This shell aims to be a comfortable experience to those familiar with traditional shell languages, but provides a powerful toolkit for interacting with programs in ways impossible before the days of WebAssembly.

If you'd like a quick overview of what wsh allows you to do (and why), see the GitHub repository. wsh is compatible with all major operating systems and architectures.

Sections

Getting Started

A guide for installing and setting up the shell.

Using the Shell

A complete and comprehensive look into the features of wsh.

POSIX Migration

A quick start for people who want to translate their bash or zsh skills to wsh.

Project Status

A page dedicated to the features that haven't landed in wsh, but are planned!

Getting Started

To get started with wsh, install the binary and learn a little bit about the shell language!

Installing

Since this project is still in infancy (see Project Status), the best way to install wsh is through Rust's package manager, cargo. In the future, more package managers, along with pre-built binaries, will be supported.

After installing the binary, you may start it up wsh:

$ wsh
Welcome to wsh, the WebAssembly shell!

~/code $

wsh is compatible with all major operating systems and architectures.

Using cargo

wsh can be installed using cargo, though crates.io. This will build the project using Rust. The minimum supported Rust version (MSRV) is 1.75.0 (you can check with rustc --version. If you do not have cargo, follow the instructions at this link.

$ cargo install wsh
...

Building from source

First, you can clone the repository, with:

$ git clone https://github.com/dzfrias/wsh
$ cd wsh

Then, you can build the project with cargo. Make sure that you have version 1.75.0 at least (you can check with rustc --version). There are no external (non-Rust) dependencies needed. However, if you'd like to run the testsuite, make sure to clone the submodules with git submodule update --init.

$ cargo run --release
...

A Tour of wsh

On a base level, wsh aims to be similar to bash and zsh. Every-day usage will resemble the aforementioned languages quite a bit. However, wsh differs a lot in its programmatic features. wsh can resemble that of a modern scripting language, if needed. You'll find that the control flow, arithmetic, syntax, and semantics are much less arcane than the POSIX standard.

The base usage

To get started, start up wsh and run the cd built-in to move to your home directory.

$ cd
$ echo hi from wsh!
hi from wsh!
$ pwd
/Users/dzfrias

Piping, from POSIX-style shells, remains the same:

$ echo "how many words here?" | wc -w
       4

Redirection is also present:

$ echo "put this in a file" > out.txt
$ echo "append this" >> out.txt
$ cat out.txt
put this in a file
append this

Capture the stdout of a command with backticks:

$ cat `echo Cargo.toml`
...

Create an alias with the alias key word:

$ alias foo = echo I don't want to type this again
$ foo
I don't want to type this again

Hopefully, these tools are enough to get you started using wsh! See the POSIX migration chapter for some more differences between wsh and traditional shells. You can read a more detailed dive into running commands in this chapter.

wsh as a scripting language

While a lot of the every-day usage experience will be similar to that of traditional shells, wsh has a powerful escape hatch. You can use the . character to escape to a language akin to a regular scripting language:

$ .x = 10
$ echo .(x + 100 == 110)
true
$ echo .("string" + " concat")
string concat
$ # yes, there's type coersion
$ .(1 + "1")
2

For the full power of language, create a new file, example.wsh.

echo hello from this script!
.var = 10
while var > 0 do
  echo .var
  .var = var - 1
end

if var == 0 then
  echo BLAST OFF!
else
  echo basic math broke in the shell...
end

Run the script with the source built-in.

$ source example.wsh
hello from this script!
10
9
8
7
6
5
4
3
2
1
BLAST OFF!

You can read more about wsh's programmatic capabilities in this chapter.

Using the Shell

This section provides a detailed look into the features currently supported by wsh.

Running Commands

Running commands in wsh is similar to that of other shells, following the <COMMAND> <ARGS>... standard.

$ echo "Hello, World!"
Hello, World!

Piping

Piping can be achieved with the | (pipe) token:

$ echo pipe! | tee out.txt | xargs echo cool
cool pipe!
$ cat out.txt
pipe!

This will pipe stdout, not stderr. The stderr stream can easily be redirected into stdout, if needed:

$ cargo build %| wc -l
       1

Note: %| in wsh is equivalent to 2>&1 in POSIX shells; see the migration guide for similar discrepencies.

Redirection

You can redirect to different files with the > and >> characters. > will create (or overwrite) a file and fill it with the received input. >> is the same as >, but will append to the file instead of overwriting it if it already exists.

$ echo hello > out.txt
$ echo append >> out.txt
$ cat out.txt
hello
append

They can accept any expression on the right hand side (i.e. string concatenation):

$ echo important stuff > .("hi" + ".txt")

Like the regular pipe operator, you can use the % character to redirect stderr along with stdout:

$ cargo build %> cargo_out.txt
$ cargo build %>> cargo_out.txt

Note: Unlike POSIX shells, redirect symbols must terminate a pipeline. For example, the parser will not succeed with:

echo hello > out | cat

Output capture

You can use backticks to capture a command result into a string:

$ .x = `cat large_file.txt`
$ .x
...

The above example uses variable assignment.

Status codes

You can get the exit status of any command using the ? character. This will be stored as a number.

$ msityped
wsh: command not found: msityped
$ echo .? .(? + 100)
127 227

Programming

Numbers

Strings

Conditions

Loops

Functions

WebAssembly

Sandboxing

Loading

memfs

Linking

Environment

Configuration

Configuration in wsh is largely done through the .wshrc file. This file will be executed on startup! .wshrc has different locations depending on your operating system, for example:

LinuxmacOSWindows
/home/dzfrias/.wshrc/Users/dzfrias/.wshrcC:\Users\dzfrias\.wshrc

Make sure to replaced dzfrias with your machine's name. If the file does not already exist, feel free to just create it at that location! There are three main things to put in a config file:

  1. Aliases
  2. Functions
  3. Environment variables

Aliases

Aliases allow you to set up custom names for commands and their arguments. For example, here are two aliases for echo:

alias foo = echo
alias bar = echo hello world

Now, when in the shell,

$ foo nice
nice
$ bar
hello world

Make sure to restart the shell when a change to the .wshrc file is made! Aliases can also represent pipelines:

alias long = echo hello world | wc -w | xargs word count:
$ long
word count: 2

Functions

Main chapter

Functions are much more powerful than aliases, and allow you to create custom commands with arbitrarily complex behavior!

def func : x do
  echo hello world
  if x > 3 then
    echo greater than 3!
  else
    echo less than or equal to 3!
  end
end

This function uses conditionals, and takes in an argument.

$ func 10
hello world
greater than 3!
$ func 1
hello world
less than or equal to 3!

For more details on the nuances of functions in wsh, see the Functions chapter.

Note: Functions must be declared at the top level of your program. This, for example, is not allowed by the parser:

if true then
  def func do
    echo hi
  end
end

Aliases, however, can be declared conditionally.

Environment variables

Main chapter

You can set environment variables using the export keyword. This will allow all spawned subprocesses read the variable.

export HELLO = this is the value

In the shell,

$ echo $HELLO

Built-ins

POSIX Migration

Project Status

This project is not finished yet! Mainly, there are a few POSIX-shell features that aren't supported in wsh at this point. There are also many things that are still under consideration, so do not expect the language to be stable. Some syntax hasn't been completely decided on yet, but most semantics should stay the same.

That being said, this project aims to be as polished as possible, so the WebAssembly features and the language implementation should be sound.

Planned Features

Here are some things that are planned, but haven't landed yet:

  • Process substitution
  • Windows >> (append redirection) support
  • Collection data structures (lists, maps)
  • For loops
  • Job control
  • Signal handling
  • Completion scripts

Contributing

If you'd like to help out with implementing any of these features, feel free to fork the repository and send in a PR!