Crush Builtin Reference

289 commands · 43 namespaces

comp

global:comp

Comparison operators

comp:eq

comp:eq left=any right=any

True if left side is equal to right side

Output

bool

In expression mode, this method can be used via the the == operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

eq 10 5
(10 == 5)

comp:gt

comp:gt left=any right=any

True if left side is greater than right side

Output

bool

In expression mode, this method can be used via the the > operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

gt 10 5
(10 > 5)

comp:gte

comp:gte left=any right=any

True if left side is greater than or equal right side

Output

bool

In expression mode, this method can be used via the the >= operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

gte 10 5
(10 >= 5)

comp:lt

comp:lt left=any right=any

True if left side is less than right side

Output

bool

In expression mode, this method can be used via the the < operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

lt 10 5
(10 < 5)

comp:lte

comp:lte left=any right=any

True if left side is less than or equal than right side

Output

bool

In expression mode, this method can be used via the the <= operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

lte 10 5
(10 <= 5)

comp:neq

comp:neq left=any right=any

True if left side is not equal to right side

Output

bool

In expression mode, this method can be used via the the != operator.

This command accepts the following arguments:

  • left the left side of the comparison.

  • right the right side of the comparison.

Examples

ne 10 5
(10 != 5)

comp:not

comp:not argument=bool

Negates the argument

Output

bool

In expression mode, this method can be used via the the ! operator.

This command accepts the following arguments:

  • argument the value to negate.

Examples

not $true
(!$true)

cond

global:cond

Logical operators (and and or)

cond:and

and condition:(bool|command)... -> boolean

True if all arguments are true

Every argument to and must be either a boolean or a command that returns a boolean. The and command will check all arguments in order, and if any of them are false, and will return false. If all conditions are true, and returns true.

Do note that and is a short circuiting command, meaning that if one of the conditions is found to be false, and will not evaluate any remaining closures.

In expression mode, this method can be used via the the and operator.

Examples

# true, if $file exists and is a symlink
and $($file:exists) {$(stat $file)[0]:is_symlink}

# true, if $file exists and is a symlink
($file.exists() and {stat($file)[0].is_symlink})

cond:or

or condition:(bool|command)... -> boolean

True if any argument is true

Every argument to or must be either a boolean or a command that returns a boolean. The or command will check all arguments in order, and if any of them are true, or will return true. If all conditions are false, or returns false.

Do note that or is a short circuiting command, meaning that if one of the conditions is found to be true, or will not evaluate any remaining closures.

In expression mode, this method can be used via the the or operator.

Examples

$stat_out := $(stat $file)[0]

# true, if $file is either a symlink or a directory
or $stat_out:is_symlink $stat_out:is_dir

# true, if $file is either a symlink or a directory
($stat_out.is_symlink or $stat_out.is_dir)

constants

global:constants

Language constants

control

global:control

Commands for flow control, (loops, etc)

The language's control-flow and process-execution builtins: conditionals and loops (if, match, while, loop, for), error handling (try, throw), job control (bg, fg, sleep, timeout), running external commands (cmd), and script-level utilities like source, which, and help itself. Imported into the global scope, so e.g. control:if and bare if are the same command -- in practice everything here is almost always written bare, since these are effectively the language's own keywords.

control:assert

control:assert condition=bool [message=string]

Error out if the condition is false.

Output

empty

This command accepts the following arguments:

  • condition the condition to check.

  • message (default: "Assertion failed") the message to show if the condition is false.

Examples

assert (1 + 1 == 2)
assert ($x > 0) "x must be positive"

control:bg

control:bg job=integer

Resume a paused job, letting it continue running in the background.

Output

empty

Unlike a job started with a trailing & (which is in the background from the moment it starts), bg acts on a job that already exists and is currently paused (e.g. via crush:pause) -- it resumes it without putting it in the foreground the way fg would.

This command accepts the following arguments:

  • job the job id of the paused job to resume in the background.

control:cmd

control:cmd command=file [<any>=any...] [arguments=any...]

Execute an external command

Output

binary_stream

Globs are file-expanded. Argument and switch order is preserved.

This command accepts the following arguments:

  • command The file path to the command to execute

  • <any>=$any Switches to pass in to the command. The name will be prepended with a double dash '--', unless it is a single character name, in which case a single dash '-' will be prepended

  • arguments Arguments to pass in to the command

control:continue

control:continue

Break execution of the current iteration of a loop and continue to the next lap.

Output

empty

control:fg

control:fg [job=integer]

Return the output of a background pipeline

A job started with a trailing & runs in the background and registers its eventual result for later retrieval; fg waits for and returns that result.

This command accepts the following arguments:

  • job the job id of the background job to put into the foreground.

Examples

# Create a pipe
$pipe := $($(table_input_stream value=$integer):pipe)
# Create a job that writes 100_000 integers to the pipe and put this job in the background
seq 100_000 | pipe:write &
# Create a second job that reads from the pipe and sums all the integers and put this job in the background
$sum_job_handle := $(pipe:read | sum &)
# Close the pipe so that the second job can finish
pipe:close
# Put the sum job in the foreground
fg $sum_job_handle

control:for

control:for [<any>=any...] body=command

Execute a command once for each element in a stream.

This command accepts the following arguments:

  • <any>=$any the name to bind each element to, as name=stream (exactly one pair).

  • body the block to execute once per element, with the bound name available as a variable.

Examples

# Iterate over the processes on the host
for i=$(host:procs) {
  echo $("Iterating over process {}":format $i:name)
}
# Print ten messages
for i=$(seq to=10) {
  echo $("Lap #{}":format $i)
}
# for is real grammar in expression mode too -- the loop variable is written
# with a $ sigil there (`for $i = ...`), not the bareword `name=stream` form
# command mode uses
assert (({
    $sum := 0
    for $i = $(seq 1 5) {
        $sum = ($sum + $i)
    }
    $sum
}()) == 10)

control:help

control:help [topic=any] [format=string]

Show help on the specified value.

Output

empty

The help command will show you help about a thing that you pass in. If you, for example pass in an integer (e.g. help 3), then you will see a help message about how crush represents integers and what methods an integer holds. You can also pass in any command to help (e.g. help $files for help on the files command). Note that you will need to prepend the $ sigil to the command name, since you're not using it as the command name.

If help's input is a pipeline, help shows help on the value in the pipeline. Otherwise, if a topic argument is given, help shows help on that value instead. With neither, help shows this introductory message.

This command accepts the following arguments:

  • topic the topic you want help on.

  • format (default: terminal, allowed: html, markdown, terminal) output format. The default, terminal, will render the help directly into the terminal. The other formats return a string containing either an html fragment or markdown.

Examples

# Show this message
help $help
# Show help on the root namespace
help $global

control:if

control:if condition=bool true_clause=command [else=string] [false_clause=command]

Conditionally execute a command once.

This command accepts the following arguments:

  • condition the condition to filter on.

  • true_clause the command to invoke if the condition is true.

  • false_clause the (optional) command to invoke if the condition is false.

Examples

if ($a > 10) {
  echo big
} else {
  echo small
}
# if is real grammar in expression mode too, with the exact same syntax
assert ((if ($a > 10) { "big" } else { "small" }) == "big")

control:loop

control:loop body=command

Repeatedly execute the body until the break command is called.

Output

empty

This command accepts the following arguments:

  • body the command to repeatedly invoke.

Examples

loop {
  if $(i_am_tired) {
    break
  }
  echo Working
}
# loop is real grammar in expression mode too, with the exact same syntax
assert (({
    $i := 0
    $sum := 0
    loop {
        if ($i >= 5) { break }
        $sum = ($sum + $i)
        $i = ($i + 1)
    }
    $sum
}()) == 10)

control:match

control:match subject=any body=command

Branch on a value against a sequence of cases.

The body is a block containing a sequence of arms, where each arm is one of:

  • case <value> {<body>} matches if the subject equals <value>.

  • any <stream> {<body>} matches if the subject equals any individual value produced by reading <stream> (e.g. $(seq 5 10) or a list).

  • is <type> {<body>} matches if the subject's type is <type>.

  • default {<body>} always matches.

Arms are tried in order; the first one that matches runs, and the rest are skipped. If nothing matches, match errors.

This command accepts the following arguments:

  • subject the value to match against.

  • body a block containing the match's arms.

Examples

match $x {
    case 2 {echo "$x is 2"}
    any $(seq 5 10) {echo "$x is between 5 and 10"}
    is $string {echo "$x is a string"}
    default {echo "I don't know what $x is"}
}
# match is real grammar in expression mode too, with the exact same syntax
assert ((match $x {
    case 2 {"two"}
    any $(seq 5 10) {"between 5 and 10"}
    is $string {"a string"}
    default {"something else"}
}) == "two")

control:return

control:return [value=any]

break execution of a closure command and optionally return a value.

The return command can only be used when inside of a closure command. Closure blocks can not break early using the return command. Do note that you can use the return command inside of a closure block which is nested arbitrarily deeply inside of a closure command, which will stop execution of all inner blocks and return the closure command.

This command accepts the following arguments:

  • value the value to return

Examples

# Define a factorial command
$factorial := {
  |$number: $integer|
  if ($number == 1) {
    return 1
  } else {
    return ($number * factorial($number - 1))
  }
}
# Call the command
factorial 5

control:schedule

control:schedule interval=duration [initial_delay=duration] [command=command] [--schedule_at_fixed_rate] [--once]

Schedule events at specified time intervals

  • If a command is specified, timer will run the command at the specified cadence.

  • If timer is used inside a pipeline, it will read one row of input at the specified cadence and write it out again.

  • Otherwise, timer will simply write an empty row at the specified cadence.

If a command fails, the timer will stop.

This command accepts the following arguments:

  • interval the interval between heartbeats.

  • initial_delay the delay for the first heartbeat. If no initial delay is specified, use the interval parameter.

  • command a command to run at each heartbeat.

  • schedule_at_fixed_rate (default: false) if heart beat delivery starts blocking, catch up by sending more heartbeats afterwards.

  • once (default: false) only schedule a single heartbeat. After that, exit.

Examples

# Show one row of the pipeline output every second
files / --recurse | schedule $(duration:of seconds=1)
# Wait for a second and then print hello once
schedule $(duration:of seconds=1) command={ echo hello } --once

control:sleep

control:sleep duration=duration

Pause execution of commands for the specified amount of time

This command accepts the following arguments:

  • duration the time to sleep for.

Examples

sleep $(duration:of seconds=10)

control:source

control:source [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Evaluate files into current crush session

This command accepts the following arguments:

  • files the files to source

Examples

source *.crush

control:throw

control:throw error_type=string message=string

Raise a custom error, catchable and discriminable by its own error type.

Output

empty

Unlike every other error in Crush, a thrown error's type (as seen via catch {|$e| ...}'s $e:type) is error_type itself, not a fixed name tied to whatever went wrong internally -- so a script or library can define and catch its own error categories.

This command accepts the following arguments:

  • error_type the error's type, e.g. "NotFound". Visible to a catch block as $e:type.

  • message the error's message. Visible to a catch block as $e:message.

Examples

try { throw "NotFound" "no such user" } catch {|$e| assert ($e:type == "NotFound")}

control:timeit

control:timeit it=command [number=integer] [repeat=integer]

Execute a command many times and estimate the execution time.

This command accepts the following arguments:

  • it the command to time.

  • number the number of runs in each repeat. If unspecified, timeit will repeat enough times for each batch to take roughly 0.4 seconds.

  • repeat (default: 5) repeat count. The average speed in the fastest repeat will be returned.

Examples

timeit {files|sort size}

control:timeout

control:timeout duration=duration command=command

Run a command, terminating it if it hasn't finished within the given duration.

If command finishes before duration elapses, timeout returns its result normally. Otherwise, a termination signal is sent to it -- the same cooperative mechanism crush:terminate uses, which only a command that actually checks for it (like sleep) will actually stop for; most builtins don't, and will keep running in the background regardless -- and timeout itself fails with a timeout error.

A command left running this way isn't just background noise: crush waits for every spawned thread to finish before the whole session exits, so a command that never cooperates and never finishes on its own (an infinite loop, for example) will keep the script -- or the whole interactive session -- from exiting cleanly, even though timeout itself already returned its error.

This command accepts the following arguments:

  • duration how long to let the command run before terminating it.

  • command the command to run.

Examples

timeout $(duration:of seconds=5) {sleep $(duration:of seconds=30)}

control:timer

control:timer it=command

Execute a command once and return the execution time.

Output

duration

This command accepts the following arguments:

  • it the command to time.

Examples

timer {files|sort size}

control:try

control:try body=command [catches=any...]

Execute a command, recovering from any error it produces.

If body fails, execution of body stops at the failing statement. Zero or more catch <filter>? {...} clauses may follow body, each the literal word catch, an optional filter (a string, glob, or regex -- anything implementing __is__, same as like/=~/match's is arm), and a block.

On failure, clauses are tried in order; the first one whose filter matches the error's type field (see below) -- or that has no filter at all -- runs, and the rest are skipped. Its block receives a struct describing the error as its single unnamed argument: message (the error text), type (the internal error variant's name, e.g. IOError, or a custom type set via throw), and command (the name of the command that failed, if known -- empty otherwise).

If no clause's filter matches, the error propagates normally, exactly as if try had no catch clauses of its own. With no catch clauses at all, an error is recovered from silently -- execution continues normally with whatever comes after try.

This command accepts the following arguments:

  • body the command to attempt.

  • catches zero or more catch <filter>? {...} clauses: the literal word catch, an optional filter pattern, and a block to run if that filter matches the error's type (or always, if no filter is given).

Examples

try {
  risky:command
} catch {
  |$error| echo ("Recovered: {}":format($error:message))
}
try {
  risky:command
} catch ^(Serde) {
  |$e| echo ("Serialization error: {}":format($e:message))
} catch Dns* {
  |$e| echo ("DNS error: {}":format($e:message))
}
# try/catch is real grammar in expression mode too, with the exact same syntax
# -- except a glob filter like Dns* above needs $(...) there, since glob literals
# only parse in command mode
assert ((try {
    throw("DnsTimeout", "no response")
} catch ^(Serde) {
    |$e| "serde"
} catch $(Dns*) {
    |$e| "dns"
}) == "dns")

control:which

control:which command=string

Find the path of an executable

Output

file

which searches the directories of the $crush:end[PATH] enivornment variable list for the specified command and returns the path to the first match.

This command accepts the following arguments:

  • command the name of the command to find.

Examples

# Returns '/bin/ps'
which ps

control:while

control:while condition=command [body=command]

Repeatedly execute the body for as long the condition is met.

Output

empty

The loop body is optional. If not specified, the condition is executed until it returns false. This effectively means that the condition becomes the body, and the loop break check comes at the end of the loop.

This command accepts the following arguments:

  • condition the condition.

  • body the command to invoke as long as the condition is true.

Examples

while {./some_file:exists} {echo "hello"}
# while is real grammar in expression mode too -- the condition is a bare
# expression there, not wrapped in its own {...} block like in command mode
assert (({
    $i := 0
    $sum := 0
    while ($i < 5) {
        $sum = ($sum + $i)
        $i = ($i + 1)
    }
    $sum
}()) == 10)

crush

global:crush

Information about this Crush session

The crush namespace holds state and controls for the running Crush process itself, as distinct from state about the external world (host) or the data flowing through a pipeline. This is where you configure the prompt and title, the warning log and syntax highlighting, read and write OS environment variables, inspect running jobs and threads, and control how the shell exits. See docs/config.md for a guided tour of what's configurable here.

crush:exit

crush:exit [status=integer] [--force]

Exit the shell

Output

empty

If other jobs are still running, exit fails with an error unless force is set, in which case those jobs are terminated first.

This command accepts the following arguments:

  • status (default: 0) The exit status to set for the process

  • force (default: false) Terminate all running jobs

crush:pause

crush:pause jid=integer

Pause the given job.

Output

empty

This command accepts the following arguments:

  • jid The job id for the job to pause

crush:resume

crush:resume jid=integer

Resume the given job.

Output

empty

This command accepts the following arguments:

  • jid The job id for the job to resume

crush:run_mode

crush:run_mode

Returns how crush is currently running, either interactive or non-interactive.

Output

string

In interactive mode, the prompt is shown and commands are entered interactively with access to history, keyboard shortcuts, etc. In non-interactive mode, no prompt is shown and commands are read from a file. The run mode can not be changed while crush is running. It is decided by how crush was started.

crush:terminate

crush:terminate jid=integer

Terminate the given job.

Output

empty

A job may continue running for some time after receiving a termination notification. Output pipelines produced by the job will still be readable and will contain any buffered IO already sent to the job before it received the termination notification.

This command accepts the following arguments:

  • jid The job id for the job to terminate

Examples

# Create a job that produces a lot of output
$all_files := $(files --recurse /)
# Read a few lines of output
$all_files | head
# Find the job id of the job we want to terminate
crush:jobs
# Ask the job to terminate.
crush:terminate 1
# This will output the number of buffered rows that were buffered
$all_files | count

crush:byte_unit

global:crush:byte_unit

Formating style for table columns containing byte sizes.

crush:byte_unit:set

crush:byte_unit:set byte_unit=string

Set the current byte unit.

Output

empty

This command accepts the following arguments:

  • byte_unit the new byte unit.

crush:env

global:crush:env

Environment variables

crush:locale

global:crush:locale

Locale data for Crush

crush:locale:set

crush:locale:set locale=string

Set the current locale.

Output

empty

This command accepts the following arguments:

  • locale the new locale.

crush:prompt

global:crush:prompt

Prompt data for Crush

crush:prompt:set

crush:prompt:set [prompt=command]

Set a new prompt command.

Output

empty

This command accepts the following arguments:

  • prompt The new command to invoke in order to produce a prompt

crush:title

global:crush:title

Title data for Crush

crush:title:set

crush:title:set [title=command]

Set a new title command

Output

empty

This command accepts the following arguments:

  • title The new command to invoke in order to produce a title

crush:warn

global:crush:warn

Warnings reported by commands that experienced a partial failure

crush:warn:list

crush:warn:list

List recent warnings reported by commands that experienced a partial failure.

Output

table_input_stream timestamp=$time command=$string message=$string file=$string location=$string

Commands that continue past a partial failure (e.g. one bad row out of a stream) report it as a warning rather than aborting. A bounded number of the most recent warnings are kept here (see crush:warn:limit); in interactive mode, they are also printed as soon as they happen, unless disabled (see crush:warn:print).

crush:warn:new

crush:warn:new message=string

Report a warning to the bounded log crush:warn:list keeps.

Output

empty

Every builtin that presses on past a partial failure (each/where/group/files, and others) reports it through this exact same mechanism instead of aborting; this is that mechanism made directly callable, for a script or closure that wants to flag something without stopping.

This command accepts the following arguments:

  • message the warning message to report.

Examples

crush:warn:new "something looked off, continuing anyway"

crush:warn:limit

global:crush:warn:limit

How many warnings crush:warn:list keeps before evicting the oldest

crush:warn:limit:set
crush:warn:limit:set limit=integer

Set how many warnings crush:warn:list keeps before evicting the oldest.

Output

empty

This command accepts the following arguments:

  • limit the new warning limit.

crush:warn:print

global:crush:warn:print

Whether warnings are printed to the screen as they happen

crush:warn:print:set
crush:warn:print:set print=bool

Set whether warnings are printed to the screen as they happen.

Output

empty

Only takes effect in interactive mode -- a warning is always recorded in crush:warn:list either way, this only controls whether it's also printed immediately. Defaults to true.

This command accepts the following arguments:

  • print whether to print warnings to the screen as they happen.

Examples

crush:warn:print:set $false

dns

global:dns

DNS querying and metadata

DNS, the Domain Name System (https://en.wikipedia.org/wiki/Domain_Name_System), is the internet's distributed naming system -- it translates human-readable domain names like example.com into the numeric IP addresses computers actually use to connect to each other, along with a handful of other record types (mail servers, text records, service discovery, ...).

It's hierarchical and distributed rather than a single lookup table: no one server holds every record. A name is resolved by delegating from root servers down through top-level-domain servers to the domain's own authoritative servers, though in practice a query is usually answered by a caching resolver (see dns:nameserver) long before it needs to walk that whole chain.

dns:domain

dns:domain

DNS domain, if any

Output

any

Reads the local domain configured in /etc/resolv.conf's domain line, if any -- no network query is made. Returns $empty if none is configured.

dns:nameserver

dns:nameserver

List of default nameservers

Reads the nameservers configured in /etc/resolv.conf -- no network query is made. This is exactly what dns:query/dns:query_reverse themselves fall back to when their own nameserver argument is left unset (specifically, the first one listed).

dns:query

dns:query name=string [record_type=string] [--tcp] [nameserver=string] [port=integer] [--no_follow_cname] [timeout=duration]

Look up a DNS record

The columns of the returned table depend on record_type:

  • A, AAAA, NS, PTR, and CNAME: target (string) and ttl (duration)

  • MX: target, preference (integer), and ttl

  • SRV: target, priority, weight, port (all integer), and ttl

  • TXT: text (binary) and ttl

  • SOA: mname, rname (strings), serial (integer), and refresh, retry, expire, and ttl (all durations)

If a response's first answer is a CNAME record, it's followed transparently and the query is retried against the alias's target -- up to 8 hops, after which a chain that still hasn't resolved is a hard error rather than being followed forever (a spoofed or compromised nameserver could otherwise cause unbounded recursion, since plain UDP DNS has no cryptographic integrity). Set no_follow_cname=$true, or query for the CNAME record type directly, to see the alias itself instead of following it.

If nameserver isn't given, the first nameserver listed in /etc/resolv.conf is used (see dns:nameserver). name is always looked up exactly as given -- unlike most system resolvers, this does not consult /etc/resolv.conf's search domains (see dns:search_paths) to expand an unqualified name.

This command accepts the following arguments:

  • name DNS record to look up.

  • record_type (default: A, allowed: A, AAAA, CNAME, MX, NS, PTR, SOA, SRV, TXT) DNS record type.

  • tcp (default: false) use TCP as the transport instead of UDP.

  • nameserver the nameserver to talk to. If none is given, use the nameservers configured in /etc/resolv.conf.

  • port (default: 53) port to talk to the nameserver on.

  • no_follow_cname (default: false) if a CNAME record is encountered, do not follow it. Show the actual CNAME record instead.

  • timeout (default: 5s) connection timeout.

Examples

dns:query "www.google.com" AAAA
dns:query "example.com" MX
# See the alias itself instead of transparently following it
dns:query "www.example.com" CNAME

dns:query_reverse

dns:query_reverse address=string [--tcp] [nameserver=string] [port=integer] [timeout=duration]

Perform a reverse DNS lookup on a given IP address

Looks up the hostname associated with address via a PTR record, automatically building the reverse-lookup name DNS uses for this (e.g. under in-addr.arpa for IPv4, ip6.arpa for IPv6) -- address should be given as a plain, forward IP address, not already reversed. Returns the hostname as a plain string, or nothing if no PTR record exists for that address. Unlike dns:query, this never follows a CNAME; a reverse zone is not expected to contain one.

This command accepts the following arguments:

  • address IP address to look up. Can be either IPv4 or IPv6.

  • tcp (default: false) Use TCP connection instead of UDP

  • nameserver Override the nameserver to talk to

  • port (default: 53) DNS port

  • timeout (default: 5s) Connection timeout.

Examples

dns:query_reverse "127.0.0.1"

dns:search_paths

dns:search_paths

List of DNS search paths

Reads the DNS search domains configured in /etc/resolv.conf -- no network query is made. A system resolver normally appends these, in order, to an unqualified hostname before giving up (e.g. trying host.example.com when asked to resolve plain host); dns:query does not apply this itself -- name is always looked up exactly as given.

fs

global:fs

File system functionality

Commands for working with the filesystem: listing and stat-ing files (files, stat), changing directory (cd), computing disk usage (usage), listing mount points (mounts), and watching a path for changes (watch). Imported into the global scope, so e.g. fs:cd and bare cd are the same command.

fs:cd

fs:cd destination=one_of $string $file $glob $re

Change to the specified working directory.

Output

empty

This command accepts the following arguments:

  • destination the new working directory.

fs:cwd

fs:cwd

Return the current working directory.

Output

file

fs:files

fs:files [directory=one_of $string $file $glob $re...] [--recurse] [permissions=bool] [--inode] [links=bool] [user=bool] [group=bool] [size=bool] [--blocks] [modified=bool] [--accessed] [type=bool] [file=bool]

Show information about files and directories

If given no arguments, list the contents to the current working directory. If given any unnamed arguments, those will be the files and directories to list.

By default, files will not recurse into subdirectories. You can override this using the --recurse switch.

This command accepts the following arguments:

  • directory directories and files to list

  • recurse (default: false) recurse into subdirectories

  • permissions (default: true) show permissions

  • inode (default: false) show inode number

  • links (default: true) show link count

  • user (default: true) show username

  • group (default: true) show group name

  • size (default: true) show file size

  • blocks (default: false) show block count

  • modified (default: true) show modification time

  • accessed (default: false) show time of last file access

  • type (default: true) show file type

  • file (default: true) show file name

fs:mounts

fs:mounts

List filesystem mount points

Output

table_input_stream size=$integer available=$integer usage=$float format=$string readonly=$any name=$string path=$file

mounts outputs the following information about each mount point:

  • size size in bytes.

  • available available space in bytes.

  • usage usage percentage.

  • format filesystem type (ntfs, ext4, etc.).

  • readonly whether the filesystem is mounted readonly.

  • name name assigned to this mountpoint, if any.

  • path the mount location.

fs:stat

fs:stat [destination=one_of $string $file $glob $re...] [--symlink]

Return a row with information about each file

Output

table_input_stream is_socket=$bool is_symlink=$bool is_file=$bool is_block=$bool is_dir=$bool is_char=$bool is_fifo=$bool inode=$integer nlink=$integer uid=$integer gid=$integer size=$integer block_size=$integer blocks=$integer access_time=$time modification_time=$time creation_time=$time file=$file

The return value contains the following columns:

  • is_socket (bool) is the file is a socket

  • is_symlink (bool) is the file a symbolic link

  • is_block (bool) is the file a block device

  • is_dir (bool) is the file is a directory

  • is_char (bool) is the file a character_device

  • is_fifo (bool) is the file a fifo

  • inode (integer) the inode number of the file

  • nlink (integer) the number of hardlinks to the file

  • uid (integer) The user id of the file owner

  • gid (integer) The group id of the file owner

  • size (integer) File size in bytes

  • block_size (integer) The size of a single block on the device storing this file

  • blocks (integer) The number of blocks used to store this file

  • access_time (time) The last time this file was accessed

  • modification_time (time) The last time this file was modified

  • creation_time (time) The time this file was created

  • file (path) The filename

This command accepts the following arguments:

  • destination the files to show the status for.

  • symlink (default: false) stat symlinks, not the files they point to.

fs:usage

fs:usage [directory=one_of $string $file $glob $re...] [--silent] [--all]

Calculate the recursive directory space usage.

Output

table_input_stream size=$integer blocks=$integer file=$file

This command accepts the following arguments:

  • directory the files to calculate the recursive size of.

  • silent (default: false) do not show directory sizes for subdirectories.

  • all (default: false) write sizes for all files, not just directories.

fs:watch

fs:watch path=one_of $string $file $glob $re [--recurse]

Watch a path for filesystem changes and stream them as rows.

Output

table_input_stream path=$file kind=$string timestamp=$time

Uses the operating system's native filesystem notification API (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows), so what counts as a change and how quickly it is reported is a best-effort property of the host OS, not a cross-platform guarantee -- rapid changes may be coalesced, and exact granularity differs by platform.

This command accepts the following arguments:

  • path the path to watch.

  • recurse (default: false) also watch subdirectories.

Examples

fs:watch . --recurse | where {kind == "Create(File)"}

groups

global:groups

User group commands

Commands for querying user groups on this system -- groups:list for every group and its gid, and lookup by name via groups[name]. Sibling to users, but for groups rather than individual accounts.

grpc

global:grpc

gRPC connection

grpc:connect

grpc:connect host=string @ $(one_of $string $glob $re) [--plaintext] [timeout=duration] [port=integer]

Create a connection to a gRPC service.

gRPC (https://grpc.io) is Google's open-source, high-performance RPC framework, built on HTTP/2 and Protocol Buffers.

To send RPC calls to a server, you must first create a grpc connection, writing something like $conn := $(grpc:connect host=localhost service=* --plaintext).

The resulting connection struct will have one method for each endpoint on the chosen services of the host you connected to. When calling a method, there are two different ways to pass in input parameters.

If you want to pass exactly one message to the endpoint, e.g. because the endpoint does not use client streaming, you have the option of passing the fields of the message as arguments to the method call, e.g. $conn:ReverseString input=hello. The grpc methods support tab completion of argument names. They also come with help messages (e.g. help $conn:ReverseString) that describes the input and output format.

If you want to pass multiple messages to the endpoint, you must do so by piping in a table_input_stream, where the column names of the stream are identical to the field names of the message, e.g. list:of foo bar baz | select input={$value} | $conn:ReverseString

Output from a gRPC method call is always a $table_input_stream, with one row per message. If an endpoint does not use server side streaming, the output always has one row.

Once you are done with a gRPC connection, you should close it to free up resources. Do so by calling the close method, e.g. $conn:close.

This command accepts the following arguments:

  • host the host to connect to.

  • service the service to connect to on this host. This can be a string, a glob or a regular expression, in order to allow you to easily specify multiple services, e.g. use * to connect to all available services.

  • plaintext (default: false) use plaintext instead of TLS to connect.

  • timeout (default: 5s) the timeout for making calls.

  • port (default: 50051) the port to connect to.

Examples

$conn := $(grpc:connect host=localhost service=* --plaintext)
# Returns "olleh"
$conn:ReverseString input="hello"
# Returns a stream with the values "oof", "rab", and "zab"
list:of foo bar baz | select input={$value} | $conn:ReverseString
# Close the connection once you're done
$conn:close

host

global:host

Information about the host this crush session is running on

Information about the machine this Crush session is running on: memory, battery, uptime, process and thread tables, and (nested further) host:os and host:cpu for operating-system and CPU-specific metadata. Contrast with crush, which is about the Crush process itself, not the machine underneath it.

host:memory

host:memory

memory usage of this host.

Output

struct

The output struct contains the following fields:

  • total, total amount of memory available to the host

  • free, unused memory

  • avail, available memory

  • swap_total, total amount of swap available to the host

  • swap_free, unused swap

host:signal

host:signal [pid=integer...] [signal=string]

Send a signal to a set of processes

Output

empty

The set of existing signals is platform dependent, but common signals include SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT and SIGWINCH.

This command accepts the following arguments:

  • pid the id of the process to send to.

  • signal (default: SIGTERM) the name of the signal to send.

Examples

# Create a `killall` command that kills any process whose name matches the specified pattern
# The pattern can be a an exact string, a wildcard, or a regex
$killall := { |$victim| host:signal @$(host:procs|where {$name =~ $victim}|select pid | list:collect) signal=SIGKILL}
# Kill all crush commands
killall ^(crush)

host:cpu

global:host:cpu

Metadata about the CPUs of this host

host:os

global:host:os

Metadata about the operating system this host is running

io

global:io

Data serialization I/O

Reading and writing structured data in specific wire formats -- json, yaml, toml, csv, hex, base64, and percent encoding, and Crush's own native pup format, each its own to/from pair. Also home to a few general-purpose I/O commands that don't belong to any one format: http, echo, readline, and member/members for pulling data out of a struct or stream. Imported into the global scope, so e.g. io:json:from and bare json:from are the same command.

io:dir

io:dir [value=any]

List the member names of a value.

Output

list $string

Works on any value -- a struct's own fields, a scope's local variables, or (for anything else, including a type value like $float) the methods its type declares.

If dir's input is a pipeline, dir lists the members of the value in the pipeline. Otherwise, dir requires a value to be provided as an argument, and lists the members of that value instead.

Pair with member to fetch one of the listed names -- member's own name argument, unlike the : operator, can be a runtime value instead of a fixed word in the source, so the two together let you enumerate and read members whose names aren't known ahead of time.

This command accepts the following arguments:

  • value the value to list the members of.

Examples

dir .
# The full help text of every method float has
dir $float | each {|$name| help ($float | member $name)}

io:echo

io:echo [values=any...] [--raw]

Prints all arguments directly to standard output.

Output

empty

If no arguments are passed to the values parameter, print the input pipeline value instead.

This command may at first appear pointless, since values entered on the prompt are printed to standard output by default. But that is only true when running a command interactively. When executing a file or running a closure, results are either completely ignored or returned as the return value of the block. In these situations, the echo command is useful for making sure a given value is written to standard output.

This command accepts the following arguments:

  • values the values to print.

  • raw (default: false) do not escape control characters in string values.

Examples

# These command invocations are equivalent
echo "Hello, world!"
"Hello, world!" | echo

io:http

io:http uri=string [method=string] [form=one_of $file $string $binary $binary_input_stream $glob $re] [header=string...] [timeout=duration]

Make a http request

Returns a struct with the following fields:

  • status_code (integer) the http status code of the reply

  • status_name (string) the name associated with the http status code

  • header (list) the http headers of the reply

  • body (binary_stream) the content of the reply

The http status codes and corresponding names are defined in https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

This command accepts the following arguments:

  • uri URI to request

  • method (default: GET, allowed: GET, POST, PUT, DELETE, HEAD, OPTIONS, CONNECT, PATCH, TRACE) the HTTP method to use in this request.

  • form form content, if any.

  • header HTTP headers, must be on the form "key:value".

  • timeout (default: 5s) connection timeout.

Examples

http "https://example.com/" header=$("Authorization: Bearer {}":format $token)

io:member

io:member field=string [value=any]

Extract one named member from a value.

Works like the : member operator, except the member name is a runtime value (e.g. a variable) rather than a fixed word in the source -- use this when the name to look up isn't known until the script runs. Pair with dir to discover a value's member names first.

If member's input is a pipeline, member extracts the named member from the value in the pipeline. Otherwise, member requires a value to be provided as an argument, and extracts the named member from that value instead.

This command accepts the following arguments:

  • field the member to extract.

  • value the value to extract the member from.

Examples

$uri := "https://raw.githubusercontent.com/liljencrantz/crush/refs/heads/master/example_data/dinosaurs.json"
http $uri | member body | json:from
# member also takes its value as an argument instead of a pipe
member __neg__ 5
# dir lists a value's member names; member fetches one by name -- together
# they let you enumerate members whose names aren't known ahead of time
for name=$(dir 5) { echo (member $name 5) }

io:members

io:members

List the columns of any streamable input value as name/type pairs.

Output

table_input_stream name=$string type=$type

Works on anything that can be read as a stream of rows -- a table, a list, a dict, a struct, a scope -- and reports that stream's shape without consuming any of its actual rows.

Examples

$my_dict | members

io:readline

io:readline [prompt=string] [history=string]

Read a string of input from the user.

Output

string

The readline command uses the same keyboard shortcuts as crush itself uses internally.

This command accepts the following arguments:

  • prompt (default: "crush# ") the prompt to show the user.

  • history load and save history under specified name.

Examples

# Ask the user for their name
echo "What is your name?"
$name := $(readline prompt="name: ")
echo $("Hello, {}!":format $name)

io:val

io:val value=any

Return value

Output

any

This command is useful if you want to pass a command as input in a pipeline instead of executing it. It is different from the echo command in that val sends the value through the pipeline, whereas echo prints it to screen.

This command accepts the following arguments:

  • value the value to pass as output.

Examples

val $val

io:base64

global:io:base64

Base64 conversions

io:base64:from

io:base64:from [files=one_of $file $string $binary $binary_input_stream $glob $re...] [alphabet=string]

Read a Base64 value and decode it.

Output

binary_stream

If no file is specified, use the input, which must be a binary or a string.

The standard alphabet follows RFC 4648, and uses a-z, A-Z, 0-9, +, and /. The urlsafe alphabet uses a-z, A-Z, 0-9, -, and .. Both use = for padding.

This command accepts the following arguments:

  • files the files to read from. Read from input if no file is specified.

  • alphabet (default: standard) base64 encoding style to use.

Examples

# Will output hello, world!
"aGVsbG8sIHdvcmxkIQ==" | base64:from

io:base64:to

io:base64:to [file=one_of $string $file $glob $re] [alphabet=string]

Write specified binary or string as Base64

Output

binary_stream

If no file is specified, produce a binary stream as output.

The standard alphabet follows RFC 4648, and uses a-z, A-Z, 0-9, +, and /. The urlsafe alphabet uses a-z, A-Z, 0-9, -, and .. Both use = for padding.

This command accepts the following arguments:

  • file the file to write to. Write to output if no file is specified.

  • alphabet (default: standard) base64 encoding style to use.

Examples

# Will output aGVsbG8sIHdvcmxkIQ==
"hello, world!" | base64:to

io:bin

global:io:bin

Binary data I/O

io:bin:from

io:bin:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Read specified files (or input) as a binary stream

If no file is specified, the input must be either binary or a string which will be converted to a binary using utf-8.

This command accepts the following arguments:

io:bin:to

io:bin:to [file=one_of $string $file $glob $re]

Write specified iterator of strings to a file (or convert to BinaryStream) separated by newlines

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

io:csv

global:io:csv

CSV I/O

io:csv:from

io:csv:from [files=one_of $file $string $binary $binary_input_stream $glob $re...] [<any>=type...] [separator=string] [head=integer] [trim=string]

Parse specified files as CSV files

This command accepts the following arguments:

  • files source. If unspecified, will read from input, which must be a binary or binary_stream.

  • <any>=$type name and type of all columns.

  • separator (default: ',') column separator.

  • head (default: 0) skip this many lines of input from the beginning.

  • trim trim this character from start and end of every value.

Examples

csv:from separator="," head=1 name=$string age=$integer nick=$string

io:hex

global:io:hex

Hexadecimal conversions

io:hex:from

io:hex:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Read a hexadecimal value and decode it.

Output

binary_stream

If no file is specified, use the input, which must be a binary or a string.

This command accepts the following arguments:

  • files the files to read from (read from input if no file is specified).

Examples

"68656c6c6f2c20776f726c6421" | hex:from

io:hex:to

io:hex:to [file=one_of $string $file $glob $re]

Write specified binary or string as hexadecimal

Output

binary_stream

If no file is specified, produce a binary stream as output.

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

Examples

"hello, world!" | hex:to

io:json

global:io:json

JSON I/O

io:json:from

io:json:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Parse json format

When deserializing a list, json:from will try to infer the type of the list. If all of the elements of the list are of the same type, the list will be parametrized to the same type. If all elements are objects, and all objects have the same set of fields with the same types, the list will be turned into a table.

This command accepts the following arguments:

Examples

http "https://jsonplaceholder.typicode.com/todos/3"| member body | json:from

io:json:to

io:json:to [file=one_of $string $file $glob $re] [--compact]

Serialize to json format

When serializing a list, some types have to be squashed, because json does not have all the same types that Crush does:

  • time values are turned into strings in the RFC 3339 format.

  • duration values are turned into the integer number of seconds in the duration.

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

  • compact (default: false) Disable line breaking and indentation.

Examples

files | json:to

io:lines

global:io:lines

Line based I/O

io:lines:from

io:lines:from [files=one_of $file $string $binary $binary_input_stream $glob $re...] [--skip_empty_lines] [--strip_whitespace]

Read specified files (or input) as a table with one line of text per row

Output

table_input_stream line=$string

This command accepts the following arguments:

  • files the files to read from (read from input if no file is specified).

  • skip_empty_lines (default: false) do not emit empty lines.

  • strip_whitespace (default: false) strip whitespace from beginning and end of lines.

io:lines:to

io:lines:to [file=one_of $string $file $glob $re]

Write specified stream of strings to a file (or convert to BinaryStream) separated by newlines

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

io:percent

global:io:percent

Percent-encoding (URL-style) conversions

io:percent:from

io:percent:from [input=string]

Decode a percent-encoded string.

Output

string

Replaces every %XX escape with the byte it represents. Errors if the decoded bytes aren't valid UTF-8.

This command accepts the following arguments:

  • input the percent-encoded string to decode. Reads a string from input if unspecified.

Examples

# Returns "a b/c"
percent:from "a%20b%2Fc"

io:percent:to

io:percent:to [input=string]

Percent-encode a string for safe use in a URL.

Output

string

Escapes every byte except the RFC 3986 unreserved set -- ASCII letters, digits, and -_.~ -- as %XX. This is the strictest common encoding, safe to use for a single path segment, query key, or query value. It does escape / and &, so don't apply it to an already-assembled path or query string, only to one component of one.

This command accepts the following arguments:

  • input the string to percent-encode. Reads a string from input if unspecified.

Examples

# Returns "a%20b%2Fc"
percent:to "a b/c"

io:pup

global:io:pup

Pup I/O

io:pup:to

io:pup:to [file=one_of $string $file $glob $re]

Serialize to pup format

Pup is the native crush serialization format. All Crush types, including lambdas can be serialized to this format.

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

Examples

files | pup:to

io:split

global:io:split

Configurable word splitting I/O

io:split:from

io:split:from [files=one_of $file $string $binary $binary_input_stream $glob $re...] separator=string [trim=string] [--allow_empty]

Read specified files (or input) as a table, split on the specified separator characters.

This command accepts the following arguments:

  • files the files to read from (read from input if no file is specified).

  • separator characters to split on

  • trim characters to trim from start and end of each token.

  • allow_empty (default: false) allow empty tokens.

io:toml

global:io:toml

TOML I/O

io:toml:from

io:toml:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Parse toml format

Input can either be a binary stream or a file. All Toml types except datetime are supported. Datetime is not supported because the rust toml library currently doesn't support accessing the internal state of a datetime.

When deserializing a list, toml:from will try to infer the type of the list. If all of the elements of the list are of the same type, the list will be parametrized to the same type. If all elements are objects, and all objects have the same set of fields with the same types, the list will be turned into a table.

This command accepts the following arguments:

Examples

toml:from Cargo.toml

io:toml:to

io:toml:to [file=one_of $string $file $glob $re]

Serialize to toml format

If no file is specified, output is returned as a BinaryStream. The following Crush types are supported: File, string, integer, float, bool, list, table, table_input_stream, struct, time, duration, binary and binary_stream.

When serializing a list, some types have to be squashed, because toml does not have all the same types that Crush does:

  • time values are turned into strings in the RFC 3339 format.

  • duration values are turned into the integer number of seconds in the duration.

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

Examples

$(files)[0] | toml:to

io:words

global:io:words

Word splitting I/O

io:words:from

io:words:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Read input and split on word boundaries.

Input can be files or the input pipe, which must be a binary input stream, split on word boundaries, trim away punctuation and discard empty "words".

This command accepts the following arguments:

  • files the files to read from (read from input pipe if no file is specified).

io:yaml

global:io:yaml

YAML I/O

io:yaml:from

io:yaml:from [files=one_of $file $string $binary $binary_input_stream $glob $re...]

Parse yaml format

When deserializing a list, yaml:from will try to infer the type of the list. If all of the elements of the list are of the same type, the list will be parametrized to the same type. If all elements are objects, and all objects have the same set of fields with the same types, the list will be turned into a table.

This command accepts the following arguments:

Examples

(http "https://jsonplaceholder.typicode.com/todos/3"):body | yaml:from

io:yaml:to

io:yaml:to [file=one_of $string $file $glob $re]

Serialize to yaml format

When serializing a list, some types have to be squashed, because yaml does not have all the same types that Crush does:

  • time values are turned into strings in the RFC 3339 format.

  • duration values are turned into the integer number of seconds in the duration.

This command accepts the following arguments:

  • file destination file to write to. If unspecified, output is returned as a binary_stream.

Examples

files | yaml:to

math

global:math

Math commands

math:abs

math:abs number=$(one_of $float $integer)

The absolute value of number.

This command accepts the following arguments:

  • number the number to take the absolute value of.

Examples

math:abs -5

math:acos

math:acos number=$(one_of $float $integer)

The arc cosine of number.

Output

float

This command accepts the following arguments:

  • number the value, between -1 and 1, to take the arc cosine of.

math:asin

math:asin number=$(one_of $float $integer)

The arc sine of number.

Output

float

This command accepts the following arguments:

  • number the value, between -1 and 1, to take the arc sine of.

math:atan

math:atan number=$(one_of $float $integer)

The arc tangent of number.

Output

float

This command accepts the following arguments:

  • number the value to take the arc tangent of.

math:ceil

math:ceil number=$(one_of $float $integer)

The smallest integer larger than number.

Output

float

This command accepts the following arguments:

  • number the number to round up to the nearest integer.

math:cos

math:cos number=$(one_of $float $integer)

The cosine of number.

Output

float

This command accepts the following arguments:

  • number the number to take the cosine of, in radians.

Examples

math:cos 1

math:exp

math:exp number=$(one_of $float $integer)

e (Euler's number) raised to the power of number.

Output

float

The same result is available as math:pow math:e number, but exp doesn't require knowing about the e constant, and its dedicated implementation is generally more numerically precise than going through a general-purpose pow.

This command accepts the following arguments:

  • number the exponent to raise e to.

Examples

# Returns 1, since e^0 is 1
math:exp 0

math:floor

math:floor number=$(one_of $float $integer)

The largest integer smaller than number.

Output

float

This command accepts the following arguments:

  • number the number to round down to the nearest integer.

math:ln

math:ln number=$(one_of $float $integer)

The natural logarithm of number.

Output

float

This command accepts the following arguments:

  • number the number to take the natural logarithm of.

math:round

math:round number=$(one_of $float $integer)

Number rounded to the nearest whole number.

Output

float

This command accepts the following arguments:

  • number the number to round to the nearest whole number.

math:sign

math:sign number=$(one_of $float $integer)

-1, 0 or 1 depending on the sign of number.

This command accepts the following arguments:

  • number the number to inspect the sign of.

Examples

math:sign -5

math:sqrt

math:sqrt number=$(one_of $float $integer)

The square root of number.

Output

float

This command accepts the following arguments:

  • number the number to take the square root of.

math:tan

math:tan number=$(one_of $float $integer)

The tangent of number.

Output

float

This command accepts the following arguments:

  • number the number to take the tangent of, in radians.

random

global:random

Random number generation

random:float

random:float to=$(one_of $float $integer)

generate a random floating point number between 0 (inclusive) and 1 (exclusive)

Output

float

This command accepts the following arguments:

  • to (default: 1.0) upper bound (exclusive).

random:float_stream

random:float_stream to=$(one_of $float $integer)

generate a stream of random floating point numbers between 0 (inclusive) and 1 (exclusive)

Output

table_input_stream value=$float

This command accepts the following arguments:

  • to (default: 1.0) upper bound (exclusive).

Examples

# Generate 20 floating point numbers between 0 and 100
random.float_stream 100 | head 20

random:integer

random:integer [to=integer]

generate a random integer between 0 and 1 (or some other specified number)

Output

integer

This command accepts the following arguments:

  • to (default: 2) upper bound (exclusive).

random:integer_stream

random:integer_stream [to=integer]

generate a stream of random integer numbers between 0 (inclusive) and 2 (exclusive)

Output

table_input_stream value=$integer

This command accepts the following arguments:

  • to (default: 2) upper bound (exclusive).

Examples

# Generate 20 integers between 0 and 100
random.integer_stream 100 | head 20

remote

global:remote

Remote code execution

Commands for running code on other machines over SSH: remote:exec runs a closure on one host, remote:pexec runs it across several in parallel, and remote:identity lists the identities your ssh-agent has loaded. remote:host tracks known-hosts entries, the same trust store ssh itself uses.

remote:exec

remote:exec command=command host=string [username=string] [password=string] [host_file=one_of $string $file $glob $re] [--ignore_host_file] [--allow_not_found]

Execute a command on a remote host

Serializes command (a closure), sends it over SSH to host, runs it there in a fresh crush process, and returns its result. The remote host's key is checked against host_file unless ignore_host_file is set. Security note: setting ignore_host_file disables that check entirely (no protection against a different host answering at that address); allow_not_found instead trusts an unrecognized host's key on first use and saves it, rather than erroring -- both weaken protection against a machine-in-the-middle impersonating the remote host.

This command accepts the following arguments:

  • command the command to execute.

  • host host to execute the command on.

  • username username on remote machines.

  • password password on remote machines. If no password is provided, agent authentication will be used.

  • host_file (~/.ssh/known_hosts) known hosts file.

  • ignore_host_file (default: false) skip checking the know hosts file.

  • allow_not_found (default: false) allow missing hosts in the known hosts file. Missing hosts will be automatically added to the file.

Examples

remote:exec {host:name} "my-server.example.com" username="alice"

remote:pexec

remote:pexec command=command [host=string...] [parallel=integer] [username=string] [password=string] [host_file=one_of $string $file $glob $re] [--ignore_host_file] [--allow_not_found]

Execute a command on a set of hosts

Output

table_input_stream host=$string result=$any

Like exec, but runs command on every host listed in host (up to parallel of them at a time). pexec always attempts every host in the list, regardless of whether earlier hosts failed to connect or authenticate -- it never fails outright just because some, or even all, of the hosts couldn't be reached. A host that succeeds contributes one row (host/result columns) to the output; a host that fails contributes no row at all. Instead, the failure is logged as a warning (see crush:warn:list) naming the host and the underlying error. pexec's own exit status stays 0 either way, so the only way to tell whether every host succeeded is to compare the length of the output to the length of the host list you passed in -- fewer output rows than hosts means some connections failed. The same host-key verification applies independently to each host -- see exec for what ignore_host_file/allow_not_found mean for security.

This command accepts the following arguments:

  • command the command to execute.

  • host hosts to execute the command on.

  • parallel (default: 32) maximum number of hosts to run on in parallel.

  • username username on remote machines.

  • password password on remote machines. If no password is provided, agent authentication will be used.

  • host_file (~/.ssh/known_hosts) known hosts file.

  • ignore_host_file (default: false) skip checking the know hosts file.

  • allow_not_found (default: false) allow missing hosts in the known hosts file. Missing hosts will be automatically added to the file.

Examples

remote:pexec {host:name} "web1.example.com" "web2.example.com" username="alice"

remote:host

global:remote:host

Known remote hosts

sockets

global:sockets

List opened sockets

Lists the TCP and UDP sockets currently open on this machine -- the same information tools like netstat or ss report. Read-only: this namespace can tell you what's listening or connected, but (unlike grpc:connect or io:http) has no way to open a connection of its own.

stream

global:stream

Stream handling commands

Crush's pipes carry typed streams of rows, not bytes -- stream is where the SQL-like operations on those streams live: filtering (where), sorting, grouping, aggregating, joining two streams, deduplicating, and more. This namespace is imported into the global scope, so every command here works equally well as stream:sort or the bare word sort -- most Crush pipelines are built by chaining these together with |.

stream:all_match

stream:all_match condition=command

True if condition is true for every row of input.

Output

bool

Stops reading input as soon as one non-matching row is found, rather than always consuming the whole stream. True for an empty input, same as an empty and chain would be. The columns of the row are exported to condition by name, exactly like where.

This command accepts the following arguments:

  • condition the condition to check for each row.

Examples

# Are all processes owned by root?
host:procs | all_match {($user == "root")}

stream:any_match

stream:any_match condition=command

True if condition is true for at least one row of input.

Output

bool

Stops reading input as soon as one matching row is found, rather than always consuming the whole stream. The columns of the row are exported to condition by name, exactly like where.

This command accepts the following arguments:

  • condition the condition to check for each row.

Examples

# Is there any process using more than 50% of a CPU core?
host:procs | any_match {($cpu > 50)}

stream:avg

stream:avg [field=string]

Calculate the average for the specific column across all rows.

If the input only has one column, the column name is optional. The column type must be numeric or a duration.

This command accepts the following arguments:

  • field The name of the column to find the average of

Examples

host:procs | avg cpu

stream:concat

stream:concat [field=string] [separator=string]

Concatenate all values of the specified column across all rows

If the input only has one column, the column name is optional. The column can be numeric, or textual.

This command accepts the following arguments:

  • field The name of the column to concatenate

  • separator (default: ", ") The separator to insert between each element

Examples

host:procs | concat name ":"

stream:count

stream:count

Count the number of rows in the input.

Output

integer

The input type can be any type that can be streamed, such as a table, a list, etc. If the input type is not a materialized type, such as a $table_input_stream, the whole stream will be consumed by this operation. Materialized types, i.e. $table, $list and $dict, have a know size, and count will not need to iterate over them to find it.

Examples

# Returns the number of processes on the system
host:procs | count

stream:drop

stream:drop [drop=string...]

Drop specified columns from input stream, copy content of remaining columns into output

This command is does the opposite of the select command. It copies all columns except the ones specified from input to output.

This command accepts the following arguments:

  • drop the columns to remove from the stream.

Examples

# Drop memory usage columns from output of ps
host:procs | drop vms rss

stream:each

stream:each body=command

Runs a command one for each row of input

Output

empty

The columns of the row are exported to the environment using the column names.

This command accepts the following arguments:

  • body the command to run.

Examples

host:procs | where {$status != "Sleeping"} | each {echo ("{} is sleepy":format $name)}

stream:fold

stream:fold initial=any body=command

Accumulate a single result across all rows of input using a user-supplied closure.

body is called once per input row, with the accumulator available as acc and the row's own columns exported by name, exactly like where/each. Its return value becomes the accumulator for the next row; once the input is exhausted, the final accumulator is fold's own output. This is the general escape hatch for one-off aggregations that don't have (or don't need) their own dedicated command like sum or max.

This command accepts the following arguments:

  • initial the accumulator's value before the first row is processed.

  • body called once per row with the accumulator (acc) and the row's own columns as named arguments; its return value is the next accumulator.

Examples

# Sum 1 through 5 by hand
seq 1 6 | fold {($acc + $value)} initial=0
# Build a comma separated string from a column
files | fold {("{}, {}":format($acc, $file))} initial=""

stream:group

stream:group [group_by=string...] [<any>=command...]

Group stream by the specified column(s)

This command accepts the following arguments:

  • group_by the column(s) to group by and copy into the output stream.

  • <any>=$command create additional columns by aggregating the grouped rows using the supplied aggregation command. The supplied command will be called once for each group, with a table_input_stream containing all rows within that group. Whatever the command outputs will be the value for the specified column for that group.

Examples

# Group files in current tree by the number of hardlinks pointing to them, show
# the number of files and the sum total file size for each link count. Sort results
# by size.
files --recurse | group links file_count=$count size={sum size} | sort size

stream:head

stream:head [rows=integer]

Return the first row(s) of the input.

Output

A stream with the same columns as the input

This command accepts the following arguments:

  • rows (default: 10) the number of rows to return.

stream:join

stream:join [<any>=any...]

Join two streams together on the specified keys.

This command accepts the following arguments:

  • <any>=$any Fields to join

Examples

join user=$(files) name=$(users:list)

stream:max

stream:max [field=string]

Calculate the maximum for the specific column across all rows.

If the input only has one column, the column name is optional. The column can be numeric, temporal, a string or a file.

This command accepts the following arguments:

  • field The name of the column to find the maximum of

Examples

host:procs | max cpu

stream:median

stream:median [field=string]

Calculate the median for the specific column across all rows.

If the input only has one column, the column name is optional. The column type must be numeric or a duration. If the column contains a NaN float value, median fails with an error rather than silently including it in (or excluding it from) the calculation.

This command accepts the following arguments:

  • field The name of the column to find the median of

Examples

host:procs | median cpu

stream:min

stream:min [field=string]

Calculate the minimum for the specific column across all rows.

If the input only has one column, the column name is optional. The column can be numeric, temporal, a string or a file.

This command accepts the following arguments:

  • field The name of the column to find the minimum of

Examples

host:procs | min cpu

stream:prod

stream:prod [field=string]

Calculate the product of the specified column across all rows.

Specifying the column is optional if the stream only has one column. The column type must be numeric.

This command accepts the following arguments:

  • field The name of the column to find the product of

Examples

seq 5 10 | prod

stream:rename

stream:rename [<any>=string...]

Rename one or more columns of a stream.

Output

A stream with the same columns as the input

Every argument name is the current name of a column, and its value is the new name to give it. Columns not mentioned pass through unchanged.

This command accepts the following arguments:

  • <any>=$string mapping from current column name to new column name.

Examples

files | rename file=path

stream:reverse

stream:reverse

Reverses the order of the rows in the input

Output

A stream with the same columns as the input

stream:sample

stream:sample [rows=integer]

Reservoir-sample rows rows from the input.

Output

A stream with the same columns as the input

Every row of input has an equal probability of ending up in the output, and the whole stream never has to be materialized to pick them -- only rows rows are ever held in memory at once. Output order is not the input order.

This command accepts the following arguments:

  • rows (default: 10) the number of rows to sample.

Examples

# Pick 5 pseudo-random lines out of a huge file, without reading it all into memory
lines:from big_log_file.txt | sample 5

stream:select

stream:select [copy_fields:string...] [*] [new_field=command]

Pass on some old fields and calculate new ones for each line of input

Examples

# Show only the filename and discard all other columns
files | select file

# Add an extra column to the output of files that shows the time passed since last modification
files | select * age={(time.now() - modified)}

stream:seq

stream:seq [args=integer...] [from=integer] [to=integer] [step=integer]

Return a stream of sequential numbers

With no arguments, seq counts forever starting at 0. Given one to three unnamed numbers, they're interpreted the same way Python's range does: seq to counts from 0 up to (but not including) to; seq from to starts at from instead; seq from to step also sets the step size. The from, to, and step named arguments below are equivalent to the two- and three-number unnamed forms, spelled out -- but can't be mixed with the unnamed form in the same call, since e.g. seq 3 to=10 would leave it ambiguous which one actually sets the end of the sequence.

This command accepts the following arguments:

  • args 1 to 3 numbers: to, from to, or from to step -- see the command's own long help. Can't be combined with the from/to/step named arguments.

  • from the first number in the sequence. Defaults to 0.

  • to the end of the sequence (exclusive). If not specified, the sequence will continue forever.

  • step the step size. Defaults to 1.

Examples

seq 3
# Prepend an index column to the output of the files command
zip $(seq) $(files)

stream:skip

stream:skip [rows=integer]

Skip the specified number of rows from the beginning of the stream and return the remainder.

Output

A stream with the same columns as the input

If the stream has fewer than the specified number of rows, an empty stream will be returned.

This command accepts the following arguments:

  • rows (default: 1) the number of rows to skip.

stream:sort

stream:sort [field=string...] [--reverse] [--case_insensitive]

Sort input stream based on one or more of it's columns

Output

A stream with the same columns as the input

If any sort column contains a NaN float value, sort fails with an error rather than picking an arbitrary position for it, since NaN has no defined ordering relative to other floats.

This command accepts the following arguments:

  • field the columns to sort on. Optional if input only has one column.

  • reverse (default: false) reverse the sort order.

  • case_insensitive (default: false) ignore case when sorting textual columns.

Examples

# Show the contents of the current directory, sorted first on type and then on filename
files | sort type file

stream:sum

stream:sum [field=string]

Calculate the sum for the specific column across all rows.

If the input only has one column, the column name is optional.

The column contents must be exactly one of the types $integer, $float, or $duration.

Normally, sum expects the type of the column to be the type to sum over, but sum can also sum over a column of type any, so long as there is at least one row in the table, and all the rows are actually of the same type.

This command accepts the following arguments:

  • field The name of the column to find the sum of

Examples

host:procs | sum cpu

stream:tail

stream:tail [rows=integer]

Return the last row(s) of the input.

Output

A stream with the same columns as the input

This command accepts the following arguments:

  • rows (default: 10) the number of rows to return.

stream:tee

stream:tee [branches=command...]

Duplicate the input stream into one or more side pipelines, passing the original stream through unchanged.

Output

A stream with the same columns as the input

Each branches block receives its own independent copy of every row and runs to completion as its own pipeline, in parallel with the others; its own output is discarded, so a branch is only useful for its side effects (writing to a file, counting, etc). tee's own output is the untouched original stream, so it composes directly into a larger pipeline. If a branch fails, the failure is reported via crush:warn:list rather than aborting tee or the other branches.

This command accepts the following arguments:

  • branches one or more pipelines to send an independent copy of the stream through.

Examples

# Write a snapshot to disk while continuing to filter the live stream
host:procs | tee {json:to snapshot.json} | where {($cpu > 50)}

stream:union

stream:union [streams=any...]

Concatenate two or more streams with identical column types into one.

Every row of the first stream is output, in order, followed by every row of the second stream, and so on. All streams must have identical column types.

This command accepts the following arguments:

  • streams the streams to concatenate.

Examples

union $(seq 0 3) $(seq 10 13)

stream:uniq

stream:uniq [field=string]

Only output the first row whenever multiple rows has the same value for the specified column

Output

A stream with the same columns as the input

If no column is given, the entire rows are compared.

This command does not just remove consecutive repeated column values, any repeated column values over the entire stream are removed.

This command accepts the following arguments:

  • field The field to compare.

Examples

host:procs | uniq user

stream:where

stream:where condition=command

Filter out rows from input based on condition

Output

A stream with the same columns as the input

The columns of the row are exported to the environment using the column names, i.e. if the table the where command is applied to has columns a and b, then the environment will have variables type and name, the variables $type and $name will be set to the values of the columns in the current row on each execution of the closure.

This command accepts the following arguments:

  • condition the condition to filter on.

Examples

# List all subdirectories to the current working directory
files | where {$type == directory}

stream:zip

stream:zip first=any second=any

Combine two streams of data into one containing one row of each input stream in each row of output.

If the two streams have different numbers of rows, the longer stream will be truncated to the length of the shorter one.

This command accepts the following arguments:

  • first the first stream.

  • second the second stream.

Examples

# Prepend an index column to the output of the files command
zip $(seq) $(files)

term

global:term

Constants useful for manipulating the terminal, such as changing text color and text weight.

ANSI escape code constants for styling terminal output -- colors (term:red, term:green, ...), term:bold, term:underline, and term:normal to reset. These are plain string values, not commands -- interpolate them directly into a string, e.g. via :format, most often to build a colorful crush:prompt.

types

global:types

Crush built in types and type related builtins.

Every value type Crush knows about, and the methods you can call on instances of it -- string, integer, list, dict, time, duration, table, re, glob, and the rest, each its own sub-namespace of methods (e.g. "hello":upper, $my_list:push value). Also home to the type system's own cross-cutting machinery: class (defining new types), convert, typeof, like (pattern matching), and materialize. Imported into the global scope, so both types:string and bare string refer to the same type.

types:class

types:class [parent=struct]

Create an empty new class

Output

struct

This command accepts the following arguments:

  • parent the parent type to inherit members from (if any).

Examples

# Create a class that represents a point in 2D space
$Point := $(class)
$Point:__short_help__ = "A point in 2D space"
$Point:__signature__ = "class Point"
$Point:__long_help__ = "Uses floating point numbers to represent the x and y coordinates"
$Point:__example__ = "$p := ($Point.new(1.0, 2.0))"
# Constructor takes two arguments, x and y
Point:__init__ = {
  |$x:$float $y:$float|
  $this:x = $x
  $this:y = $y
}

Point:len = {
  |
  short_help = "Returns the distance from the origin"
  |
  ($math.sqrt($this.x*$this.x + $this.y*$this.y))
}
# Overload the `+` operator to add two points. (Only available in expression mode)
Point:__add__ = {
  |
  short_help = "Add two points together"
  $other : $struct "the other point."
  |
  ($Point.new(x=($this.x+$other.x), y=($this.y+$other.y)))
}
$p := $($Point:new x=1.0 y=2.0)
$p:len
$p2 := ($Point.new(x=-1.0, y=2.0))
$p3 := ($p + $p2)

types:convert

types:convert target_type=type [value=any]

Convert the value to the specified type

Converting a value to the type it already holds always works and returns the original value. Most other conversions take the input value, convert it to a string and then attempt to parse that string as the desired type.

The following short cut conversions exist that do not go via a string representation:

  • $float to $integer the value is truncated to its integer part.

  • $integer to $bool 0 is false, all other values are true.

If convert's input is a pipeline, convert converts the value in the pipeline. Otherwise, convert requires a value to be provided as an argument, and converts that value instead.

This command accepts the following arguments:

  • target_type the type to convert the value to.

  • value the value to convert.

Examples

convert $integer 1.8

types:definition

types:definition command=command

Returns the definition of the specified closure as a text string

Output

string

Returns nothing if the command is not a closure

Note that the outputted of the definition builtin is reformatted, including switching code between expression mode and command mode.

This command accepts the following arguments:

  • command the closure to show the definition of.

Examples

# returns { $files --recursive '/'}
$all_the_files := {files --recursive /}
definition $all_the_files

types:like

types:like value=any [pattern=any...]

Check if the specified value matches one or more patterns.

Output

bool

A pattern can be a string (exact match), a glob, a regular expression, a type (checks value's type), or any other value that implements an __is__ method -- like simply calls it. If multiple patterns are given, they're checked in order and like returns true as soon as one of them matches.

In expression mode, a single pattern can also be checked via the =~ operator (or !~ for the negation).

This command accepts the following arguments:

  • value the value to test.

  • pattern the pattern(s) to test the value against.

Examples

# Match the string "fooo" against the regex ^(ooo)
like fooo ^(ooo)
# Same, in expression mode
(fooo =~ ^(ooo))
# A value matches if it equals any of several patterns
like fooo ^(ooo) *.txt "fooo"

types:materialize

types:materialize

Recursively convert all streams in io to materialized form

Examples

# Put a table of files in the current directory into the variable $f
$f := $(files | materialize)
# Because we materialized the table stream into a table, counting the elements is not a destructive operation.
$f | count

types:typeof

types:typeof [value=any]

Return the type of the specified value.

Output

type

If typeof's input is a pipeline, typeof returns the type of the value in the pipeline. Otherwise, typeof requires a value to be provided as an argument, and returns the type of that value instead.

This command accepts the following arguments:

  • value the value to provide the type of.

Examples

# Returns float
typeof 1.8

types:any

type any

Any type.

This is a wildcard type, matching a value of any other type. It shows up as the declared type of a column or argument that intentionally imposes no type restriction -- it is not a type user code constructs values of directly.

types:binary

type binary

Binary data.

A binary value can be created by converting another value, e.g. convert $binary "hi", or by reading a binary_stream to completion with materialize, e.g. bin:from ./Cargo.toml | materialize.

Binary data is immutable once created, and unlike string or file it has no legality constraint at all -- it's simply an arbitrary sequence of bytes, the type to reach for when data isn't necessarily text or a path. See help string for how the three sequence-of-data types (string, file, binary) differ. The most similar type is binary_stream, its one-shot streaming form.

types:binary:__getitem__

types:binary[index=integer]

Returns the byte at the specified offset.

Output

integer

This command accepts the following arguments:

  • index index

Examples

$(bin:from Cargo.toml)[4]

types:binary_stream

type binary_stream

A stream of binary data.

A binary_stream is obtained by reading binary data without fully loading it into memory first, e.g. bin:from ./Cargo.toml, or the body of an HTTP response from io:http.

Like table_input_stream, it can only be read once. Pipe it through materialize to get a reusable binary value instead.

types:bool

type bool

True or false.

A boolean value is one of the two literals $true or $false -- there is no other way to construct one. Booleans are immutable, and are the result type of every comparison (==, <, ...) and logical (and, or) operator.

types:command

type command

A piece fo code that can be called.

The most common way to create a command is a closure literal, e.g. {echo hello}, or with named parameters, {|$x| echo $x}. Builtin commands are themselves command values and can be captured into a variable the same way, e.g. $e := $echo.

A command value is immutable -- calling it runs its body, but that doesn't change the value itself. Reassigning the variable that holds a command is a separate operation from mutating the command.

types:dict

type dict $empty $empty

A mutable mapping from one set of values to another.

Create a dict with the dict:of command, e.g. dict:of a=1 b=2, or by collecting key/value columns out of piped table input with dict:collect.

Dicts are mutable: entries can be inserted, removed, or have their value replaced in place. The most similar type is struct, which is also a mapping from keys to values, but with a fixed set of keys chosen when the struct is created rather than a dynamic, mutable set of keys.

types:duration

type duration

A difference between two points in time.

To create your own duration objects, use the duration:of method, for example

duration:of seconds=10

A duration instance has nanosecond precision. It is represented internally as two 64 bit numbers, one for the number of seconds, and one for the nanosecond remainder.

durations are signed, i.e. they can be used to denote a negative span of time. Durations are immutable values. The most similar type is time: subtracting one time from another produces a duration, and a duration can be added to or subtracted from a time.

types:duration:__add__

duration + (delta:duration | time:time)

Add the specified delta or time to this duration.

types:duration:__div__

duration / divisor:integer

Divide this duration by the specified divisor.

Output

duration

types:duration:__mul__

duration * factor:integer

Multiply this duration by the specified factor.

Output

duration

types:duration:__sub__

duration - delta:duration

Remove the specified delta from this duration.

Output

duration

types:duration:of

types:duration:of [nanoseconds=integer] [microseconds=integer] [milliseconds=integer] [seconds=integer] [minutes=integer] [hours=integer] [days=integer]

Create a new duration.

Output

duration

Durations are stored as a time span in number of seconds. Because of leap seconds and daylight saving time, adding for example exactly one day to a time value will not always do what you might think, if a leap second or a daylight savings time changeover happened in the interim.

This command accepts the following arguments:

  • nanoseconds (default: 0) the number of nanoseconds in the duration.

  • microseconds (default: 0) the number of microseconds in the duration.

  • milliseconds (default: 0) the number of milliseconds in the duration.

  • seconds (default: 0) the number of seconds in the duration.

  • minutes (default: 0) the number of minutes in the duration.

  • hours (default: 0) the number of hours in the duration.

  • days (default: 0) the number of days in the duration. This is internally represented as the number of seconds in a standard day.

Examples

duration:of minutes=1

types:empty

type empty

Nothing.

The instance of the empty type is returned by commands that don't return any value, e.g. echo. There is no way to construct it directly -- it only ever shows up as the natural result of a command that produces no output.

types:file

type file

Any type of file.

A file value is usually written as a bareword or single-quoted path, e.g. ./Cargo.toml or 'my file.txt' -- crush recognizes these as files rather than plain strings based on their syntax. You can also convert an existing string explicitly, e.g. convert $file "./Cargo.toml".

A file value simply names a path; the value itself is immutable, though of course the file it points at on disk can change, be created, or be removed out from under it via methods like remove or commands like fs:mkdir. See help string for exactly how file differs from string and binary, the other two types that represent a sequence of data rather than a single scalar value; glob is also related, matching a whole set of paths rather than naming a single one.

types:file:__getitem__

types:file[name=$(one_of $string $file)]

Return a file or subdirectory in the specified base directory.

Output

file

This command accepts the following arguments:

  • name the name of the file or subdirectory

Examples

$filename := foo.txt
$base_directory := .
$file := $base_directory[$filename]

types:file:chmod

types:file:chmod [permissions=string...]

Change permissions of this file.

Output

empty

Permissions are strings of the form [classes...][adjustment][modes..].

  • A class is one of u, g, o, a, signifying file owner, file group, other users and all users, respectively.

  • The adjustment must be one of +, -, and =, signifying added permissions, removed permissions and set permissions, respectively.

  • A mode is one of r w, x, signifying read, write and execute permissions.

This command accepts the following arguments:

  • permissions the set of permissions to add.

Examples

./foo:chmod "a=" "u+r" # First strip all rights for all users, then re-add read rights for the owner

types:file:chown

types:file:chown [user=string] [group=string]

Change owner of this file.

Output

empty

This command accepts the following arguments:

  • user the owning user for the file.

  • group the owning group for the file.

types:file:mkdir

types:file:mkdir [--ignore_existing]

Create directory

Output

empty

This command accepts the following arguments:

  • ignore_existing (default: false) Do not throw and error if this directory already exists.

types:file:remove

types:file:remove [--recursive] [--verbose]

Delete this file

Output

table_input_stream file=$file deleted=$bool status=$string

Returns a stream of deletion failures.

This command accepts the following arguments:

  • recursive (default: false) If this file is a directory, recursively delete files and subdirectories

  • verbose (default: false) If true, emit status updates for deleted files, not just errors

types:file:touch

types:file:touch [--no_create]

Set the modification and access times of file.

Output

empty

If the file doesn't exist, it is created.

This command accepts the following arguments:

  • no_create (default: false) Do not create the file if it doesn't exist.

types:file:write

types:file:write

Write a binary_stream to this file. If no stream is given, input pipe must be one.

Output

empty

types:float

type float

A numeric type representing any number with floating point precision.

A float literal is a bare number containing a decimal point, e.g. 5.0 or -3.25.

A Crush float is a IEEE 754 64-bit (double precision) floating point number. Floats are immutable values. The most similar type is integer; mixing the two in an arithmetic expression promotes the result to a float.

types:float:__add__

types:float + term=$(one_of $float $integer) # Only available in expression mode

Add this number and the specified term and return the result

Output

float

This command accepts the following arguments:

  • term the number to add.

types:float:__div__

types:float / term=$(one_of $float $integer) # Only available in expression mode

Divide this number by the specified factor

Output

float

This command accepts the following arguments:

  • term the number to divide by

types:float:__mul__

types:float * term=$(one_of $float $integer) # Only available in expression mode

multiply this number and the specified factor and return the result

Output

float

This command accepts the following arguments:

  • term the number to multiply

types:float:__sub__

types:float - term=$(one_of $float $integer) # Only available in expression mode

Subtract the specified term from this number and return the result

Output

float

This command accepts the following arguments:

  • term the number to subtract

types:glob

type glob

A pattern containing wildcards.

Globs are usually created by writing an unescaped string containing a wildcard character (* or ?), like files *.toml.

If you want to construct a new glob from a string, use the glob:new command, e.g. glob:new "*.txt".

Globs are immutable. The most similar types are re, which supports much richer patterns at the cost of more complex syntax, and string, which globs otherwise resemble but never match by wildcard -- only a real glob value does.

types:glob:__is__

types:r#type:__is__ needle=any

True if the needle's type is this type. Not meant to be called directly -- use the like command, the =~ operator, or the is arm of a match block.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:glob:__is_not__

types:r#type:__is_not__ needle=any

False if the needle's type is this type. Not meant to be called directly -- use the like command or the !~ operator.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:glob:files

types:glob:files [directory=file]

Perform file matching of this glob.

Output

list $file

This command accepts the following arguments:

  • directory the directory to match in. Use current working directory if unspecified.

types:glob:filter

types:glob:filter [columns=string...]

Filter input stream based on this glob.

Output

A stream with the same columns as the input

Search all textual (string and file) columns for matches of the glob, and output the rows that match.

This command accepts the following arguments:

  • columns Columns to filter on. Column must be textual. If no columns are specified, all textual columns are used.

Examples

# Recursively search current directory for all files containing four `a` characters in a row
files --recurse | *aaaa*:filter

types:glob:new

types:glob:new glob=string

Create a glob from a string

Output

glob

This command accepts the following arguments:

  • glob the string representation of the glob.

types:integer

type integer

A numeric type representing an integer number.

An integer literal is a bare number, e.g. 5 or -3. Underscores may be used as digit separators to make large numbers easier to read, e.g. 1_000_000.

A Crush integer uses signed 128 bit precision. This means that the highest number that can be represented is 170141183460469231731687303715884105727, and the lowest is -170141183460469231731687303715884105728.

Integers are immutable values. The most similar type is float, used for numbers that need a fractional part; mixing an integer and a float in an arithmetic expression promotes the result to a float.

types:integer:__add__

types:integer + term=$(one_of $float $integer) # Only available in expression mode

Add this number and the specified term and return the result

This command accepts the following arguments:

  • term the number to add

types:integer:__div__

types:integer / term=$(one_of $float $integer) # Only available in expression mode

Divide this number by the specified factor

Dividing an integer by an integer zero is an error. Dividing by a float zero follows IEEE 754 (producing infinity or NaN), since the result is a float.

This command accepts the following arguments:

  • term the number to divide by

types:integer:__mod__

types:integer:__mod__ term=integer

Least positive residue after integer division

Output

integer

A divisor of zero is an error.

This command accepts the following arguments:

  • term the number to divide by

types:integer:__mul__

types:integer * term=$(one_of $float $integer) # Only available in expression mode

multiply this number and the specified factor and return the result

This command accepts the following arguments:

  • term the number to multiply

types:integer:__rem__

types:integer:__rem__ term=integer

Remainder after integer division

Output

integer

A divisor of zero is an error.

This command accepts the following arguments:

  • term the number to divide by

types:integer:__sub__

types:integer - term=$(one_of $float $integer) # Only available in expression mode

Subtract the specified term from this number and return the result

This command accepts the following arguments:

  • term the number to subtract

types:list

type list $any

A mutable list of items, usually of the same type.

Create a list with the list:of command, e.g. list:of 1 2 3, or by collecting a column out of piped table input with list:collect.

Lists are mutable: elements can be appended, removed, or replaced in place. The most similar type is table, which is also an ordered sequence of items but where each item is a row of several named, differently-typed columns rather than a single value.

types:one_of

type one_of

One of

A one_of value is constructed with the one_of:of command, e.g. one_of:of $file $string $regex, and names a set of acceptable types rather than a single one. It's used the same way an ordinary type is -- most commonly to declare that a signature parameter accepts any one of several types -- rather than being a type user code creates values of.

types:one_of:__call__

types:one_of:__call__ [types=type...]

Construct a one_of value type with the specified allowed types

Output

type

This command accepts the following arguments:

  • types The allowed types

Examples

one_of:of $file $string $regex

types:re

type re

A regular expression is an advanced pattern that can be used for matching and replacing text.

Regular expressions are usually created by writing using regexp literal syntax, e.g. files ^(^...$).

If you want to construct a new glob from a string, use the re:new command, e.g. re:new "[a-z]*\.txt".

Regular expressions are immutable. The most similar type is glob, which supports only simple wildcard patterns but with much simpler syntax.

types:re:__is__

types:r#type:__is__ needle=any

True if the needle's type is this type. Not meant to be called directly -- use the like command, the =~ operator, or the is arm of a match block.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:re:__is_not__

types:r#type:__is_not__ needle=any

False if the needle's type is this type. Not meant to be called directly -- use the like command or the !~ operator.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:re:filter

types:re:filter [columns=string...]

Filter input stream based on this regex.

Output

A stream with the same columns as the input

Search all textual (string and file) columns for matches of the regex, and output the rows that match.

This command accepts the following arguments:

  • columns Columns to filter on. Column must be textual. If no columns are specified, all textual columns are used.

Examples

# Recursively search current directory for all files containing four `a` characters in a row
files --recurse | ^(aaaa):filter

types:re:new

types:re:new pattern=string

Compile a string into a new regular expression instance.

Output

re

This command accepts the following arguments:

  • pattern the new regular expression as a string.

types:re:replace

types:re:replace text=string replacement=string

Replace the first match of the regex in text with the replacement

The replacement string may reference capture groups from the match: $0 for the whole match, $1, $2, ... for positional groups, or $name for a named group ((?P<name>...)). Use ${1} (or ${name}) instead of $1 when the reference is immediately followed by a character that would otherwise be read as part of the group number or name.

This command accepts the following arguments:

  • text the text to perform replacement on.

  • replacement the replacement text; may reference capture groups, see above.

Examples

# Replaces the first run of digits
^([0-9]+):replace "a123b456" "X"
# Swap the two halves of a dash-separated pair, using capture groups
^((.*)-(.*)):replace "123-456" "$2-$1"

types:re:replace_all

types:re:replace_all text=string replacement=string

Replace all matches of the regex in text with the replacement

The replacement string may reference capture groups from each match: $0 for the whole match, $1, $2, ... for positional groups, or $name for a named group ((?P<name>...)). Use ${1} (or ${name}) instead of $1 when the reference is immediately followed by a character that would otherwise be read as part of the group number or name.

This command accepts the following arguments:

  • text the text to perform replacement on.

  • replacement the replacement text; may reference capture groups, see above.

Examples

# Replaces every run of digits
^([0-9]+):replace_all "a123b456c789" "X"
# Swap key and value in every space-separated pair
^(([a-z]+)=([0-9]+)):replace_all "a=1 b=2 c=3" "$2=$1"

types:scope

type scope

A scope in the Crush namespace.

A scope is normally not constructed directly -- crush creates one implicitly for the root namespace ($global) and for every closure or block invocation. The scope currently executing can be obtained by calling __current_scope__ on any existing scope value, e.g. $global:__current_scope__.

Scopes are mutable: declaring a new variable (:=) or assignment (=) modifies the scope it's declared or resolved in.

types:scope:__getitem__

types:scope[name=string]

Return the specified member in the current scope

This command accepts the following arguments:

  • name the name of the member to look up.

types:scope:__resolve__

types:scope:__resolve__ name=string

Resolve the specified member in the current scope

This method looks at the current scope as well as all it parents to resolve the specified member

This command accepts the following arguments:

  • name the name of the member to resolve.

types:string

type string

Textual data, stored as an immutable sequence of unicode code points.

A string literal is written between double quotes, e.g. "hello world". A string is a sequence of legal unicode characters -- nothing else can be represented, and every crush string is guaranteed to be valid text.

Strings are immutable -- every method that looks like it modifies a string (upper, replace, trim, ...) returns a new string rather than changing the receiver.

file and binary are the two other types that hold sequences of data rather than a single scalar value, and it's worth being precise about how they differ from string and from each other. A file represents an operating system path: a sequence of bytes that is a legal file name, a system-dependent notion of legality that usually allows byte sequences that aren't legal unicode (for example, a Latin-1-encoded name on a system whose text encoding is UTF-8). A binary is simply a sequence of bytes with no legality constraint at all -- the type to reach for when the data isn't necessarily text or a path. Because "legal file name" and "legal unicode text" are overlapping but different constraints, string and file have to be separate types: some strings can't be legal file names (most commonly one containing a zero byte -- many operating systems represent a path internally as a zero-terminated byte sequence, so a zero byte can never be part of one), and some legal file names can't be represented as a string at all.

For convenience, builtin commands that expect a file argument also accept a string, which crush converts automatically. That conversion doesn't validate the result up front, though -- passing a string containing a zero byte is accepted silently, and only fails once the resulting file value is actually used against the filesystem. This isn't just an implementation shortcut: neither crush nor the computer it's running on can actually know what does and doesn't constitute a legal file name ahead of time, because that's up to whatever filesystem the path eventually resolves into, and that can change from one path component to the next -- a network mount, for instance, can enforce completely different naming rules than the local filesystem it's mounted under, and crush has no general way to know a path crosses into one before it's used. Some obviously-illegal names could be rejected early (a zero byte, for example, is illegal everywhere), but the only way to be certain a given name is legal is to actually hand it to the operating system in a real syscall. Going the other way, a file whose bytes aren't valid unicode can't be losslessly converted to a string either; rather than erroring, crush falls back to displaying it as the placeholder text <invalid filename>.

types:string:__getitem__

types:string[idx=integer]

Extract a one character substring from this string.

Output

string

This command accepts the following arguments:

  • idx index

types:string:__is__

types:r#type:__is__ needle=any

True if the needle's type is this type. Not meant to be called directly -- use the like command, the =~ operator, or the is arm of a match block.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:string:__is_not__

types:r#type:__is_not__ needle=any

False if the needle's type is this type. Not meant to be called directly -- use the like command or the !~ operator.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:string:bytes

types:string:bytes

Returns the length (in number of bytes) of the string, as encoded using UTF-8

Output

integer

Note that there are often different ways to generate identical looking strings of different lengths, as in the example below.

Examples

# Returns 2
"é":bytes
# Returns 3
"é":bytes

types:string:ends_with

types:string:ends_with suffix=string

True if this string ends with the specified suffix

Output

bool

This command accepts the following arguments:

  • suffix suffix to check for

types:string:format

types:string:format [<any>=any...] [unnamed=any...]

Format arguments into a string

Output

string

This command accepts the following arguments:

  • <any>=$any The named parameters to format into the pattern string

  • unnamed The unnamed parameters to format into the pattern string

Examples

"Hello {name}":format name=$name

types:string:is_ascii

types:string:is_ascii

True if every character of this string is part of the ascii character set

Output

bool

types:string:is_digit

types:string:is_digit [radix=integer]

True if every character of this string is a digit in the specified radix

Output

bool

"123":is_digit # true

This command accepts the following arguments:

  • radix (default: 10) radix to use

types:string:join

types:string:join [elements=any...]

Join all arguments by the specified string

Output

string

This command accepts the following arguments:

  • elements the elements to join.

Examples

# Returns "1, 2, 3, 4"
", ":join 1 2 3 4

types:string:len

types:string:len

Returns the length (in number of unicode characters) of the string.

Output

integer

Note that a unicode character is not always what a human would consider a character, and there are often different ways to generate identical looking strings with different numbers of characters, as in the example below.

Examples

# Returns 1
"é":len
# Returns 2
"é":len

types:string:lpad

types:string:lpad length=integer [padding=string]

Returns a string truncated or left-padded to be the exact specified length

Output

string

This command accepts the following arguments:

  • length the length to pad to.

  • padding (default: " ") the character to pad with.

Examples

# Returns "     Hello"
"Hello":lpad 10
# Returns "He"
"Hello":lpad 2

types:string:repeat

types:string:repeat times=integer

Returns this string repeated times times

Output

string

This command accepts the following arguments:

  • times the number of times to repeat the string.

Examples

"Around the world\n":repeat 8

types:string:rpad

types:string:rpad length=integer [padding=string]

Returns a string truncated or right-padded to be the exact specified length

Output

string

This command accepts the following arguments:

  • length the length to pad to.

  • padding (default: " ") the character to pad with.

Examples

# Returns "Helloooooo"
"Hello":rpad length=10 padding=o
# Returns "He"
"Hello":rpad 2

types:string:split

types:string:split separator=string

Splits a string using the specified separator

Output

list $string

This command accepts the following arguments:

  • separator the separator to split on.

Examples

# Returns ["Hello", "World"]
"Hello World":split " "

types:string:starts_with

types:string:starts_with prefix=string

True if this string starts with the specified prefix

Output

bool

This command accepts the following arguments:

  • prefix prefix to check for

types:string:substr

types:string:substr [from=integer] [to=integer]

Extract a substring from this string.

Output

string

This command accepts the following arguments:

  • from (default: 0) Starting index (inclusive). If unspecified, from start of string.

  • to ending index (exclusive). If unspecified, to end of string.

types:struct

type struct

A mapping from name to value.

To create a simple immutable struct, use the struct:of command, e.g. struct:of x=1 y=2; its fields can be read ($s:x) but not reassigned.

To create a mutable struct that supports inheritance and methods, use the class command; instances created from a class ($MyClass:new ...) do support field reassignment ($instance:x = 5) from outside the class as well as from within its own methods.

The most similar type is dict, which is also a mapping from keys to values, but with keys chosen at runtime rather than fixed named fields, and no support for methods or inheritance.

types:struct:join

types:struct:join [structs=struct...]

Combine any number of structs into one containing all of their members

Output

struct

On a name collision between two of the given structs, the later one's member is renamed by appending _2, _3, and so on (repeating until the generated name is unique) -- the same renaming join, zip and group already use when combining columns from more than one source, applied here to struct members instead.

Only each struct's own local members are used, not any inherited from a parent (e.g. via class) -- the same "data struct" semantics struct:of itself uses.

This command accepts the following arguments:

  • structs the structs to combine.

Examples

struct:join (struct:of a=1 b=2) (struct:of b=3 c=4)

types:struct:of

types:struct:of [unnamed=any...] [<any>=any...]

Construct a struct with the specified members

Output

struct

Unnamed arguments will be given the names _1, _2, _3, and so on.

Unlike a struct created via the class command, a struct created via struct:of does not have a parent or a __setattr__ method. The lack of a __setattr__ method means that a "data struct" is immutable, though its members may potentially be modified, depending on their type.

This command accepts the following arguments:

  • unnamed unnamed values.

  • <any>=$any named values.

Examples

struct:of foo=5 bar="baz" false

types:table

type table

A table of rows.

A table is created by piping a table_input_stream through materialize, e.g. files | materialize.

Unlike a table_input_stream, a table is a fixed snapshot: it can be read more than once, indexed by row number ($t[0]), and asked for its length ($t:len) -- but it has no methods for adding, removing, or replacing rows. The most similar type is table_input_stream, the one-shot, streaming form it's materialized from.

types:table:__call__

types:table_input_stream:__call__ [<any>=type...]

return the table_input_stream type with the specified column signature.

Output

type

You usually do this in order to create a pipe specialized to a specific column signature.

This command accepts the following arguments:

  • <any>=$type the columns of the stream.

Examples

$pipe := $($(table_input_stream value=$integer):pipe)

types:table:__getitem__

types:table_input_stream[index=integer]

Returns the specified row of the table stream as a struct.

Output

struct

This command accepts the following arguments:

  • index the row index to return.

Examples

$(files)[4]

types:table_input_stream

type table_input_stream

An input stream of table rows.

A table_input_stream is produced by any streaming command -- for example, the output of files or seq -- or by reading the read member of a pipe object (see (table_input_stream ...):pipe, under help pipe).

It can only be traversed once: each row is consumed as it's read, so a second pass over the same stream sees nothing. If you need to read the same rows more than once, pipe the stream through materialize to turn it into a reusable table. table_output_stream is the writable counterpart of the same rows.

types:table_input_stream:__call__

types:table_input_stream:__call__ [<any>=type...]

return the table_input_stream type with the specified column signature.

Output

type

You usually do this in order to create a pipe specialized to a specific column signature.

This command accepts the following arguments:

  • <any>=$type the columns of the stream.

Examples

$pipe := $($(table_input_stream value=$integer):pipe)

types:table_input_stream:__getitem__

types:table_input_stream[index=integer]

Returns the specified row of the table stream as a struct.

Output

struct

This command accepts the following arguments:

  • index the row index to return.

Examples

$(files)[4]

types:table_input_stream:pipe

types:table_input_stream:pipe

Returns a pipe consisting of a read end and a write end.

Output

struct

Each row of data in the pipe must have the columns specified by this table_input_stream specialization. A pipe is usually created by specializing table_input_stream e.g. like

$pipe := $($(table_input_stream value=$integer):pipe)

The pipe object has three methods:

  • pipe:write write sink for this pipe. Put this method at the end of a pipeline that produces data for the pipe.

  • pipe:read read source for this pipe. Put this method at the start of a pipeline that consumes data from the pipe.

  • pipe:close call this method once all readers and writers have been created in order to close the pipe.

A pipe object can have arbitrarily many write jobs producing data into the pipe. Each writer simply pipes rows into the pipe:write method.

A pipe object can have arbitrarily many read jobs consuming data from the pipe. Each reader simply consumes rows from the pipe:read method.

Each row written to the pipe will be consumed by exactly one reader job.

In order for the consumer jobs to finish, all the writer jobs must end and the pipe:close method must be called. Once this has happened and all the rows have been processed, the consumer job(s) will finish.

Note that the pipe:close method does not interrupt currently existing read or write jobs, but it does prevent new read and write jobs from being started.

Always fg every writer job before calling pipe:close (readers don't need this -- only writers). pipe:write reads the pipe's internal state on its own worker thread whenever it happens to get scheduled, with no synchronization against pipe:close; calling pipe:close before a writer job has actually had a chance to run can silently drop that writer's entire contribution.

Examples

# Create a pipe
$pipe := $($(table_input_stream value=$integer):pipe)
# Create a job that writes 100_000 integers to the pipe and put this job in the background
$write_job_handle := $(seq 0 100_000 | pipe:write &)
# Create a second job that reads from the pipe and sums all the integers and put this job in the background
$sum_job_handle := $(pipe:read | sum &)
# Put the writer job in the foreground so it fully finishes before the pipe is closed
fg $write_job_handle
# Close the pipe so that the second job can finish
pipe:close
# Put the sum job in the foreground
fg $sum_job_handle

types:table_output_stream

type table_output_stream

An output stream of table rows.

A table_output_stream is obtained from the output member of a pipe object, created by calling :pipe on a table_input_stream type, e.g. $p := $($(table_input_stream value=$integer):pipe); $p:output is then a table_output_stream that rows can be written to, and $p:read is the matching table_input_stream those same rows can be read back from.

Rows are written with the write method (see help pipe:write). The most similar type is table_input_stream, its read-side counterpart.

types:table_output_stream:__call__

types:table_output_stream:__call__ [<any>=type...]

return the table_output_stream type with the specified column signature.

Output

type

This command accepts the following arguments:

  • <any>=$type the columns of the stream.

types:time

type time

A point in time with nanosecond precision.

To get the current time, use time:now. To parse a time from text, use time:parse.

All time instances use the local time zone.

A time instance has nanosecond precision. It is represented internally as two 64 bit numbers, one for the number of seconds since the Unix epoc, and one for the nanosecond remainder.

Times are immutable values -- arithmetic methods like adding a duration return a new time rather than changing the receiver. The most similar type is duration, used to represent the difference between two times.

types:time:__add__

types:integer + term=duration # Only available in expression mode

Add the specified delta to this time

Output

time

This command accepts the following arguments:

  • term the number to add

types:time:__sub__

time - duration | time

Remove the specified duration from this time to produce an earlier time, or calculate the difference between two points in time.

types:time:format

types:time:format format=string

Format this time using a strftime-style pattern string

Output

string

Date specifiers:

  • %Y year with century.

  • %y year without century, zero padded.

  • %C century, zero padded.

  • %m month, zero padded.

  • %b abbreviated month name.

  • %h abbreviated month name.

  • %B full month name.

  • %d day of month, zero padded.

  • %e day of month, space padded.

  • %a weekday as abbreviated name.

  • %A weekday as full name.

  • %w weekday as a number, where 0 is Sunday and 6 is Saturday.

  • %u weekday as a number, where 1 is Monday and 7 is Sunday.

  • %U week number of the year (Sunday as first day of week), zero padded.

  • %W week number of the year (Monday as first day of week), zero padded.

  • %G same to %Y but uses the year number in ISO 8601 week date.

  • %g same to %y but uses the year number in ISO 8601 week date.

  • %V same to %U but uses the year number in ISO 8601 week date.

  • %j day of the year, zero-padded.

  • %D month-day-year format. Same to %m/%d/%y.

  • %x month-day-year format. Same to %m/%d/%y.

  • %F year-month-day format (ISO 8601). Same to %Y-%m-%d.

  • %v day-month-year format. Same to %e-%b-%Y. Time specifiers:

  • %H hour (24-hour clock) as a zero-padded number.

  • %k hour (24-hour clock) as a space-padded number.

  • %I hour (12-hour clock) as a zero-padded number.

  • %l hour (12-hour clock) as a space-padded number.

  • %P locale’s equivalent of either am or pm.

  • %p locale’s equivalent of either AM or PM.

  • %M minute as a zero-padded number.

  • %S second as a zero-padded number.

  • %f fractional nanoseconds since last whole seconds, zero-padded.

  • %R hour-minute format. Same to %H:%M.

  • %T hour-minute-second format. Same to %H:%M:%S.

  • %X hour-minute-second format. Same to %H:%M:%S.

  • %r hour-minute-second format in 12-hour clocks. Same to %I:%M:%S %p. Time zone specifiers:

  • %z UTC offset in the form +HHMM or -HHMM.

  • %Z time zone name.

  • %:z a colon, followed by UTC offset in the form +HHMM or -HHMM. Special characters:

  • %c ctime date & time format. Same to %a %b %e %T %Y sans \n.

  • %+ ISO 8601 / RFC 3339 date & time format.

  • %s UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC.

  • %t a literal tab character.

  • %n a literal newline character.

  • %% a literal % character.

This command accepts the following arguments:

  • format the format of the time.

Examples

time:now:format "%s"

types:time:parse

types:time:parse format=string time=string

Parse a time string using a strptime-style pattern string

Output

time

After parsing the date, it will be converted to the local time zone. Date specifiers:

  • %Y year with century.

  • %y year without century, zero padded.

  • %C century, zero padded.

  • %m month, zero padded.

  • %b abbreviated month name.

  • %h abbreviated month name.

  • %B full month name.

  • %d day of month, zero padded.

  • %e day of month, space padded.

  • %a weekday as abbreviated name.

  • %A weekday as full name.

  • %w weekday as a number, where 0 is Sunday and 6 is Saturday.

  • %u weekday as a number, where 1 is Monday and 7 is Sunday.

  • %U week number of the year (Sunday as first day of week), zero padded.

  • %W week number of the year (Monday as first day of week), zero padded.

  • %G same to %Y but uses the year number in ISO 8601 week date.

  • %g same to %y but uses the year number in ISO 8601 week date.

  • %V same to %U but uses the year number in ISO 8601 week date.

  • %j day of the year, zero-padded.

  • %D month-day-year format. Same to %m/%d/%y.

  • %x month-day-year format. Same to %m/%d/%y.

  • %F year-month-day format (ISO 8601). Same to %Y-%m-%d.

  • %v day-month-year format. Same to %e-%b-%Y. Time specifiers:

  • %H hour (24-hour clock) as a zero-padded number.

  • %k hour (24-hour clock) as a space-padded number.

  • %I hour (12-hour clock) as a zero-padded number.

  • %l hour (12-hour clock) as a space-padded number.

  • %P locale’s equivalent of either am or pm.

  • %p locale’s equivalent of either AM or PM.

  • %M minute as a zero-padded number.

  • %S second as a zero-padded number.

  • %f fractional nanoseconds since last whole seconds, zero-padded.

  • %R hour-minute format. Same to %H:%M.

  • %T hour-minute-second format. Same to %H:%M:%S.

  • %X hour-minute-second format. Same to %H:%M:%S.

  • %r hour-minute-second format in 12-hour clocks. Same to %I:%M:%S %p. Time zone specifiers:

  • %z UTC offset in the form +HHMM or -HHMM.

  • %Z time zone name.

  • %:z a colon, followed by UTC offset in the form +HHMM or -HHMM. Special characters:

  • %c ctime date & time format. Same to %a %b %e %T %Y sans \n.

  • %+ ISO 8601 / RFC 3339 date & time format.

  • %s UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC.

  • %t a literal tab character.

  • %n a literal newline character.

  • %% a literal % character.

This command accepts the following arguments:

  • format the format of the time.

  • time the time string to parse.

Examples

time:parse format="%s" time="1234567890"

types:type

type type

A type.

A type value names one of crush's own types, e.g. $string or $integer -- typeof returns a value of this kind. Types are mostly used to declare what kind of value a signature parameter or table column accepts, e.g. via convert or a class field declaration, rather than being manipulated directly by everyday scripts.

types:type:__is__

types:r#type:__is__ needle=any

True if the needle's type is this type. Not meant to be called directly -- use the like command, the =~ operator, or the is arm of a match block.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

types:type:__is_not__

types:r#type:__is_not__ needle=any

False if the needle's type is this type. Not meant to be called directly -- use the like command or the !~ operator.

Output

bool

This command accepts the following arguments:

  • needle the value whose type to check.

users

global:users

User commands

Commands for querying user accounts and login sessions on this system: users:me for the current user, users:current for everyone currently logged in (tty, login time, ...), users:list for every account that exists, and users[username] to look one up by name -- the resulting struct has a do method to run a closure as that user, e.g. users[root]:do {rm foo.txt}. This reads local system account data, not any particular authentication or identity provider.

var

global:var

Commands related to variables

Commands for working with variables and scopes directly, as values rather than through $name/:=/= syntax: declaring, setting, unsetting, reading, and destructuring, plus var:use/var:unuse for importing a scope's contents into the current one and var:list/var:local for introspecting what's currently in scope. This namespace is imported into the global scope, so e.g. var:let and bare let are the same command.

var:get

var:get name=string

Returns the current value of a variable

A variable by the specified name must already exist in some visible scope before calling the get builtin, or an error will result.

The get builtin is not normally called directly, simply prefix the $ sigil with the name of the variable you want to get.

This command accepts the following arguments:

  • name the name of the variable to return the value of.

Examples

# These two lines are equivalent
$x
var:get x

var:let

var:let [<any>=any...]

Declare new variables in the current scope.

No variable can exist in the local scope, or an error will result.

The let builtin is not normally called directly, but via the syntactic sugar of the := operator.

This command accepts the following arguments:

  • <any>=$any the variables to declare. The value you supply will be the initial value of the variable.

Examples

# These two lines are equivalent
$x := 2
var:let x=2

var:let_destructure

var:let_destructure [names=string...] value=any

Declare new variables in the current scope by destructuring a list, struct, or dict.

Not normally called directly, but via the syntactic sugar of the := operator applied to a bracketed list of names, e.g. [$a, $b] := $pair. value's elements -- a list's elements, or a struct's/dict's values in insertion order -- are declared positionally into names, in order. The number of elements must exactly match the number of names, or an error results.

This command accepts the following arguments:

  • names the names of the variables to declare, in order.

  • value the list, struct, or dict to destructure.

Examples

# These two lines are equivalent
[$a, $b] := [1, 2]
var:let_destructure a b value=[1, 2]

var:list

var:list

Returns a table containing all variable names currently in scope and their types.

Output

table_input_stream name=$string type=$string

A variable is in scope if it exists in the current scope, any of its parents, or any of the scopes used in any of those scopes.

var:set

var:set [<any>=any...]

Reassign existing variables

A variable by the specified name must already exist in some visible scope before calling the set builtin, or an error will result.

The set builtin is not normally called directly, but via the syntactic sugar of the = operator.

This command accepts the following arguments:

  • <any>=$any the variables to reassign. The value you supply will be the new value of the variable.

Examples

# These two lines are equivalent
$x = 2
var:set x=2

var:set_destructure

var:set_destructure [names=string...] value=any

Reassign existing variables by destructuring a list, struct, or dict.

Not normally called directly, but via the syntactic sugar of the = operator applied to a bracketed list of names, e.g. [$a, $b] = $pair. Every name must already exist in some visible scope, exactly like set. value's elements -- a list's elements, or a struct's/dict's values in insertion order -- are assigned positionally into names, in order. The number of elements must exactly match the number of names, or an error results.

This command accepts the following arguments:

  • names the names of the variables to reassign, in order.

  • value the list, struct, or dict to destructure.

Examples

# These two lines are equivalent
[$a, $b] = [1, 2]
var:set_destructure a b value=[1, 2]

var:unset

var:unset [name=string...]

Removes variables from the namespace

Output

empty

This command accepts the following arguments:

  • name the name of the variables to unset.

Examples

# Remove the variable x
var:unset x

var:unuse

var:unuse [name=scope...]

Make specified scopes not searched by default during scope resolution.

Output

bool

The unuse builtin will recursively go through all parent scopes and remove all uses of the provided scopes through the entire chain.

This command accepts the following arguments:

  • name the scopes to unuse.

Examples

# Stop using the stream scope
var:unuse $stream
# This command will now fail, because stream::select is not in scope
select

var:use

var:use [name=scope...]

Make specified scopes searched by default during scope resolution.

Output

empty

This command accepts the following arguments:

  • name the scopes to use.

Examples

# Import the math scope
var:use $math
sqrt 2