Mash Quick Reference Guide



String literals

Rich strings are recommended for most interactive uses, and provide the following additional features compared to basic strings:

Both single- and double-quoted strings can span multiple lines; any newline characters are retained literally in the string value.

String escapes sequences start with the backtick character `:

If bare words are enabled (using configuration property language.bareWords), then any unbound identifier is automatically promoted to a string tagged with os.Path.

Object literals

An arbitrary expression can appear as a field name, but an identifier must be enclosed in parens for this to work:

fieldName = "foo"
{ (fieldName): 42 } # => { foo: 42 }

If a variable is in scope, it can be used to name a field and provide the value in one shot:

value = "foo"
{ value } # => { value: "foo" }

Conditionals, truthiness, and/or

Mash considers the following values falsey: false, null, 0,[], {}, "". All other values are truthy.

The and and or operators work as follows:

For example:

true and true # true
dir.exists or dir.mkdir
dir.exists and

not is a standard library function.

Pipe operator

The pipe operator | is syntax sugar for function application:

Function declarations

Functions are declared using def syntax:

def square n = n * n

Multiple parameters are supported:

def add x y = x + y

Functions without parameters:

def greet = print "Hello"

A variadic parameter can take zero or many positional arguments:

$ def printAll words... = words | each print
$ printAll "foo" "bar" "baz"

Defaults values can be provided for when a parameter is omitted:

def someFunc (n = 4) = n * n
someFunc # => 16

Lazy arguments defer the evaluation of the argument until it is referenced in the body of the function:

$ def doTwice (@lazy block) = (block; block)
$ doTwice (print "Hi")

Last parameters consume the last positional argument, useful for making functions fit better into pipe syntax:

def preprend items... (@last list) = items + list
[3, 4] | prepend 1 2 # => [1, 2, 3, 4]

Functions can be nested:

def outer = {
  def inner n = n + 1
  inner 42

Function calls:

Ordinary function call syntax:

f arg1 arg2 arg3

Named argument syntax:

f --param1=arg1 --param2=arg2 --param3=arg3

Alternative parenthesis-based function call syntax:

f(arg1, arg2, arg3)

Nullary functions

Some functions and methods can be called with no arguments. For example, ls or now. If such a nullary function is referenced either using an identifier, or by a member expression (e.g. git.status), then it is immediately invoked.

If you need to obtain a reference to a nullary function or method itself, without immediately invoking it, you can use a lookup expression. For example,


A function or method is considered nullary if every parameter is either optional or variadic.

Anonymous functions and holes

Anonymous functions with a single argument:

x => x + 1
x => x.size

As syntax sugar, anonymous functions with a single argument can be written using the hole (_) operator. Same examples as above:

_ + 1

The scope of the hole is the smallest enclosing:

Holes can be repeated:

_ * _ # equivalent to x => x * x

There is a further abbreviation for member expressions:

.size # equivalent to _.size, or x => x.size

Multiple parameter functions are supported:

x y => x * y

As are empty parameter lists.

=> now + 1.hour

Member vectorisation

If a member does not exist on a sequence object, but it does on the elements of the sequence, then a member access is automatically vectorised:

ls.permissions # returns a list of Permissions objects

Mish and subprocesses

Mish is a sublanguage within Mash for launching processes, with a similar syntax to a traditional shell.

By default, Mash is in “regular Mash” mode. If a command line starts or ends with !, the entire line is interpreted as a Mish command. If ! is issued by itself as a command, then Mash toggles into Mish by default, and the prompt changes from a $ to a !.

Within Mash, you can embed Mish fragments. A !{..} expression runs a subprocess, captures the output, and returns a ProcessResult object. For example: * !{which java}.toPath * !{locate python}.lines * !{sleep 3}.duration

However, standard input is not connected to the subprocess when using !{..}. If you want to interact with a process interactively, then you can use a !!{..} expression: * !!{nano file}

Conversely, you can embed Mash fragments within Mish:

Other features

Command line


Tab completion

Hit tab once to complete methods, functions, files, arguments, etc. The list of possible completions is displayed. If you hit tab again immediately, you enter completion browsing mode, which will display additional information about the options.

Startup file: init.mash

Mash executes commands from ~/.mash/init.mash on startup and can be used to add aliases and set configuration options.

Configuration options

config.language.bareWords = false # Treat unbound identifiers as string literals
config.cli.showStartupTips = true # Show tip on startup

Standard library

Directory navigation

Working with files

Collection processing

Processes, users and groups

Dates and times

Git support