Nushell

Overview

Nushell is "a new type of shell". "The goal of this project is to take the Unix philosophy of shells, where pipes connect simple commands together, and bring it to the modern style of development." Nushell was created by Jonathan Turner, Yehuda Katz, and Andres Robalino. It runs in Linux, macOS, and Windows.

Nushell is implemented in Rust. And like Rust, Nushell produces helpful, nicely formatted error messages.

Nushell includes the Nu language which excels at "processing streams of structured data". This provides features that are somewhat like SQL for databases. It also has similarities to the Python-based Pandas data analysis library. These are features not typically seen in shell environments. It is far from a toy project and uses recursive descent parser that is driven by its many supported data types.

Nushell continues the UNIX tradition of commands whose input can be piped in from a previous command and whose output can be piped to a subsequent command. A series of commands separated by the pipe character | is referred to as a "pipeline". Commands stream their output to the next command in the pipeline. A command does not have to run to completion before the next command in the pipeline can begin receiving that output as its input.

Some commands such as echo and ls are lazy. This means they do not produce output unless something is requesting data from their output stream. Commands executed in the shell automatically have their output requested. When semicolons are used to separate multiple pipelines on the same line, the shell only requests output from the last pipeline. For example, let a = 2; let b = 3; $a + $b outputs 5.

Color coding is applied to commands as they are typed. If a command becomes invalid, all the text changes to red.

Because Rust is a great source for compiling to WebAssembly, it was possible to implement a web-based environment for experimenting with Nushell. This can be found at Nushell demo.

The Nu language can be used outside Nushell, such as in Jupyter Notebooks.

It costs nothing but some disk space to try Nushell (about 50 MB). You don't have to commit to making it your default shell. Just pop in periodically to try it and exit to return to your current shell. Over time you may decide you like it enough to make it your default shell.

Terminology

The term "pipeline" was described earlier. Command pipelines entered in the shell must be on a single line, but inside scripts lines that end with | continue on the next line. Nushell does not support using \ as a line continuation character like in other shells such as Bash.

Commands that take no input and produce output are referred to as "inputs" or "sources". An example is the open command which loads a file.

Commands that take input and transform it are referred to as "filters". Examples include the where and sort-by commands.

Commands that take input and display it or write it somewhere such as file are referred to as "outputs" or "sinks". An example is the save command.

Installing

There are many options for installing or upgrading Nushell.

If you have Rust installed, enter cargo install nu. This takes around seven minutes to complete. It installs the nu executable in $HOME/.cargo/bin which is in my PATH environment variable.

If you are on macOS and have Homebrew installed, enter brew install nushell. Note that Homebrew may install a version that is several versions behind the latest.

Prebuilt binaries for Linux, macOS, and Windows can also be downloaded.

For more information on installation options, click the Nushell link above.

If you are interested in peeking at the source code, clone the GitHub repo. To build it locally enter cargo build --release --features=extra. To see the extra features this includes, search for "extra" at Cargo.toml.

Upgrading

When a new version of Nushell comes out, here are the steps to upgrade. These have been tested in macOS, but not in other platforms.

Getting Started

After installing Nushell, enter nu in a terminal to start a shell.

For help, enter help. For a list of Nushell commands and custom commands, enter help commands. In version 0.60.0 there are 262 Nushell commands.

For help on a specific command, enter help {command-name} or {command-name} -h`. For more detail on supported commands, see the Command Reference.

Like in all shells, commands are executed by typing them and pressing the return key. Multi-line commands can be entered by pressing return before a block, delimited by square brackets or curly braces, until complete.

Nushell has great command recall and completion like the Fish and Zsh shells. Command recall even supports multi-line command editing.

When a command not defined by Nushell is encountered, the directories listed in the path configuration setting are searched to find a matching executable. To run a command in the path that happens to have the same name as a Nushell command, prefix the command name with ^.

For example, ^find -name '*.svelte' | xargs grep import uses the find command defined in root shell rather than the version defined by Nushell.

For detailed documentation on Nushell commands, see the Book link in the top nav of the Nushell website.

For more help, join the nushell Discord channel.

Subcommands

Subcommands provide a way of grouping commands under a common "namespace". Examples of such built-in namespaces include date, from, into, math, path, random, str, to, and url.

The date subcommands are format, humanize, list-timezone, now, to-table, and to-timezone.

The from subcommands convert data from a given format to a table. They are csv, eml, ics, ini, json, ods, ssv, toml, tsv, url, vcf, xlsx, xml, yaml, and yml.

The into subcommands convert values to another type. They are binary, bool, datetime, decimal, duration, filesize, int, and string. For example, echo '19' | into int gives the integer 19.

The math subcommands perform math calculations. They are abs, avg, ceil, eval, floor, max, median, min, mode, product, round, sqrt, stddev, sum, and variance.

The path subcommands operate on file paths. The table below describes these and shows the result of entering echo ~/Documents/demo.txt | path {subcommand}.

SubcommandDescription
basenamereturns the filename portion (demo.txt)
dirnamereturns the directory path (~/Documents)
existsreturns a boolean indicating if the file exists;
can only return true for expanded paths
expandreturns the expanded path (/Users/mark/Documents/demo.txt)
joinreturns the result of joining two partial paths
echo '~/Documents' | path join -a demo.txt
returns ~/Documents/demo.txt
parseconverts a path to structured data including parent (directory path), stem (filename w/o extension), and extension
relative-toreturns a path relative to another
splitreturns the parts of a path split by a separator
typereturns Dir or File

TODO: RESUME UPDATES HERE!

The query command queries various data formats. Currently the only supported subcommand is json. For example, echo '{"foo": 1, "bar": 2}' | query json bar gives the integer 2.

The str subcommands perform string operations. They are camel-case, capitalize, collect, contains, downcase, ends-with, find-replace, from, index-of, kebab-case, length, lpad, ltrim, pascal-case, reverse, rpad, rtrim, screaming-snake-case, snake-case, starts-with, substring, to-datetime, to-decimal, to-int, trim, and upcase. Also see the commands build-string, char, format, and size.

The to subcommands convert a table into a given output format and are commonly piped to the save command to write the result to a file. They are csv, html, json, md, toml, tsv, url, xml, and yaml.

The url subcommands get information from a URL. They are host, path, query, and scheme (ex. http).

Configuration

The configuration for Nushell is stored in a TOML (Tom's Obvious, Minimal Language) file whose path can be obtained by entering echo $nu.config-path. Configuration settings can be changed by editing this file or using the config subcommands described below. Changes to the config file only affect new shell sessions, not the current one.

To edit the config file with Vim, enter vim $nu.config-path. To edit the config file with VS Code, enter code $nu.config-path. When editing the config file using VS Code, consider installing the "TOML Language Support" extension which profiles syntax highlighting and formatting.

Some Nushell configuration settings are top-level and do not appear in a specific TOML section. Notable top-level options include:

SettingDescription
disable_table_indexeswhen true, omits index column from table output
pathlist of directories in quotes to search for executables
promptcommand whose output is used for the prompt
skip_welcome_messagewhen true, starting a shell doesn't output a
welcome message including the Nushell version
startuplist of commands to execute when a shell starts;
typically defines aliases and custom commands
table_modecontrols the border lines drawn when tables are rendered
(more detail below)

For details on configuration options, see Configuration.

The config command supports many subcommands that operate on the config file. These are summarized in the table below.

CommandDescription
configoutputs all the settings
config pathoutputs the file path to the configuration file
config set {name} {value}sets or updates a specific setting
{pipeline} | config set_into {name}sets a specific setting to a piped-in value
config get {name}gets a specific setting
config remove {name}removes a specific setting

For example, to change the prompt enter the following:

config set prompt "echo (ansi yellow) '🦀ν> '"

This adds the line prompt = "echo (ansi yellow) '🦀ν> '" to the configuration file. 🦀 is for the Rust mascot Ferris and ν is the Greek letter nu.

For a fancier prompt setting that includes the current working directory in yellow, and a green, right-pointing triangle at the end, add the following line in the config file:

prompt =
"echo `🦀ν {{(ansi yellow)}}{{(pwd)}}{{(ansi green)}}{{(char prompt)}} `"

Another option for customizing the prompt is to enable the use of Starship, which has many more options. It also has the advantage that it can be used with nearly any shell, which is great for users that sometimes switch between shells.

startup Setting

The startup setting specifies a list of commands to run each time a new Nushell session is started. Typically the commands define aliases and custom commands (using def). For example:

startup = [
"alias cls = clear",
"def cdjs [] { cd $nu.env.JS_DIR }",
"def cdrust [] { cd $nu.env.RUST_DIR }"
]

Some code formatters reformat TOML arrays to be on a single line which makes reading these definitions difficult. VS Code and the "TOML Language Support" extension does not do this.

Aliases that use the "cd" command currently causes Nushell to crash. See issue 3138.

table_mode Setting

Table borders can be customized with the table_mode setting. Supported values include:

color_config Section

The colors used to output data of each table element and data type can be customized by adding a [color_config] section in the config file. Supported colors include red, yellow, green, cyan, blue, purple, white, and black. Supported modifiers include bold, underline, italic, dimmed, and reverse. Colors and modifiers can be specified with their full names, separated by an underscore. For example, yellow_bold. They can also be abbreviated using only their first letters. For example, yb. The only exception is blue which uses the letter "u" because "b" is used for black.

The header elements and styles that can be configured include header_align, header_bold, header_color, index_color, leading_trailing_space_bg, and separator_color (used for table lines). The data types that can be configured include primitive_binary, primitive_boolean, primitive_columnpath, primitive_date, primitive_decimal, primitive_duration, primitive_filesize, primitive_int, primitive_line, primitive_path, primitive_pattern, primitive_range, and primitive_string.

For example:

[color_config]
header_align = "l" # use left or l, right or r, and center or c
header_bold = true
header_color = "r"
index_color = "wd" # white dimmed
separator_color = "wd" # white dimmed; for table lines

primitive_binary = "c"
primitive_boolean = "p"
primitive_date = "u"
primitive_decimal = "g"
primitive_filesize = "g"
primitive_int = "g"
primitive_path = "y"
primitive_string = "w"

line_editor Section

Nushell line editing is provided by rustyline. It can be configured with the "[line_editor]" section. Notable settings include:

SettingDescription
edit_mode"emacs" or "vi"
default is to use rustyline key bindings
history_duplicates"alwaysadd" or "ignoreconsecutive" (default)
history_ignore_spacetrue (default) or false;
when true, commands with leading whitespace are not added to history

For example:

[line_editor]
edit_mode = "vi" # omit for default keystrokes (see rustyline link above)
history_ignore_space = true

path setting

The path setting lists directories to be searched for executables.

To see a nicely formatted list of directories in your path, enter echo $nu.path or config | get path.

The command config set path $nu.path sets the path setting to the value of $nu.path, which is the value of the PATH environment variable in the parent shell. Once set, this can be customized to be specific to Nushell. Note that if Nushell is your login shell then there is no parent shell from which to inherit a path.

env Section

The command config set env $nu.env adds all the current environment variables in the env section of the config file. This section can also define environment variables that are specific to Nushell. Note that if Nushell is your login shell then there is no parent shell from which to inherit environment variables.

For example:

[env]
GITHUB_USER = "mvolkmann"

textview Section

These settings affect operation of the bat crate which is used by the open command to view text files.

SettingDescription
gridtrue (default) or false
headertrue (default) or false
line_numberstrue (default) or false
themeex. "Coldark-Dark"
true_colortrue or false
vcs_modification_markerstrue or false (seems to have no effect)

TODO: Setting vcs_modification_markers to true has no effect. See issue 3254.

To see the supported themes, install bat by entering cargo install bat and enter bat --list-themes. There are over 20.

Data Types

Unlike most shells where only strings are used for command input and output, Nushell supports many primitive and structured data types. Some types described in the Nushell documentation are purely conceptual, meaning that they cannot be used as the type of a custom command parameter. The following tables list all the real types and conceptual types.

Real Types:

TypeDescription
anyany type below (default for variables and custom command parameters)
blockblock of nu script code (can be executed on each row of a table)
durationnumber followed by a unit which can be ms, sec, min, hr, day, or wk
filesizenumber followed by a unit which can be b, kb, mb, gb, tb, or pb
intwhole number with infinite precision
numberint or decimal, both with infinite precision
pathplatform-independent path to a file or directory
patternglob pattern that can include * wildcard and ** for traversing directories
range{start}..{end} (inclusive) or {start}..<{end} (end is exclusive); use 2 dots, not 3
stringsingle words need no delimiter; multiple words need single quotes, double quotes, or backticks
tablelist of rows; returned by many Nushell commands

The ability to specify single-word literal strings with no delimiters is one of my favorite features in Nushell! It makes defining lists and tables that contain single-word strings much more compact. For example, the following line creates a list of color names.

let colors = [red orange yellow green blue purple]

Conceptual Types:

TypeDescription
binarysequence of raw bytes
booleanliteral values are $true and $false
column pathdot-separated list of nested column names
datetimezone-aware; defaults to UTC
decimalnumber with a fractional part and infinite precision
groupsemicolon-separated list of pipelines where only output from the last is output
linestring with an OS-dependent line ending
listsequence of values of any type
rowlist where each value represents a column with an associated name

Duration units for month and year are not supported because those durations vary based on the month (28 to 31) or year (normal or leap year).

To see a description of the value of an expression, pipe it to the describe command. This is not its real type. Values of type of int are reported as integer. This is likely a bug. See issue 3206. For example, date now | describe outputs date.

Details about Nushell data types can be found at Types of data.

Type Conversions

The following type conversions are supported:

TODO: Fill in the ??? in this table.

TODO: How can you create values with types binary, line, path, pattern, and row?

FromToCommand
anystringpipe to describe
booleanstringpipe to str from
datestringpipe to str from
intstringpipe to str from
liststringpipe to str collect if the list contains strings
numberstringpipe to str from
pathstringpipe to ???
patternstringpipe to ???
rangestringpipe to ???
tablestringpipe to ???
unitstringpipe to str from *
stringbooleanpipe to ???
stringdatepipe to str to-datetime
stringintpipe to str to-int
stringlistpipe to split row
stringnumberpipe to str to-decimal
stringpathpipe to ???
stringrangepipe to ???
stringtablepipe to ???
stringunitpipe to ???

* TODO: This gives an error. Why?

The echo command is often used to feed the initial value into a command pipeline. This can be a literal value or an expression such as a variable reference. For example:

echo "2021-3-21 14:30" |
str to-datetime |
date format -t '%B %-d, %Y' |
get formatted
# This outputs the string "March 21, 2021".

Formatting characters supported by date format are described here.

This handy custom command produces a string from the items in a list where the value of each item is followed by a newline character. It is used in several examples that follow. Consider adding this to the startup array in your Nushell config file.

# The `each` command iterates over list items that are piped to this command.
# During the iteration, the special variable $it (for item)
# is set to the current item.
def as-lines [] {
each { echo (build-string $it (char newline)) } | str collect
}

Strings

Strings delimited by backticks support templating (a.k.a interpolation) with expressions in pairs of double curly brackets. For example:

let x = 19; echo `x is {{$x}}`

let x = 3
let y = 5
echo `product of {{$x}} and {{$y}} is {{($x * $y)}}`
# As discussed in the "Operators" section later,
# operators can only be used in "math mode".
# An expression is in math mode if it begins with `=`.

The empty? command determines whether a string, list, or table is empty. It can be used with strings as follows:

let name = "Mark"
= $name | empty? # false

let name = ""
= $name | empty? # true

The operators =~ and !~ test whether one string contains or does not contain another.

For example:

= "foobarbaz" =~ "bar" # true
= "foobarbaz" !~ "bar" # false

The lines command creates a list of strings from a string that contains newline characters. Nushell doesn't currently support escape characters like \n, so the char command must be used to insert newlines into a literal string. For example:

let s = $"This(char newline)has(char newline)three lines."
let l = (echo $s | lines) # ["This", "has", "three lines."]

Ranges

A range represents a sequence of numbers in increments of one. For example, 2..4 represents the numbers 2, 3, and 4. Floating point numbers are supported. For example, 1.2..4.0 represents the numbers 1.2, 2.2, and 3.2. The start value can be greater than the end value to represent a decrementing sequence. For example, 4..2 represents the numbers 4, 3, and 2.

Either bound can be negative, but parentheses are required when the start value is negative. For example, (-2)..2 represents the numbers -2, -1, 0, 1, and 2. and `2..-2 represents the numbers 2, 1, 0, -1, and -2.

Values of the range type can use default values for their start or end. If the start value of a range is omitted, it defaults to zero. For example, ..10 is the same as 0..10. If the end value of a range is omitted, the range has no upper bound.

The get the starting and ending values of a range, pipe it to the first and last commands.

For example:

echo 3..7 | first # 3
echo 3..<7 | last # 6
echo 1..3 | as-lines # outputs 1, 2, and 3 on separate lines

Types With Units

Duration values with different units can be added. For example, 2hr + 57min + 11sec (my best marathon time).

Values of the filesize type with different units can be added. For example, 2mb + 57kb + 11b.

When values of different types are combined in a coercion error occurs. For example, 3hr + 2mb gives this error and clearly identifies that the first value is a duration and the 2nd is a filesize.

Lists

A list is an ordered collection of values. The literal syntax for creating a list is to include expressions in square brackets separated by spaces or commas (for readability). For example, [foo bar baz] or [foo, bar, baz].

To iterate over the elements in a list, use the each command. The $it special variable holds the output of the previous command. When used in a block passed to the each command, it holds the current item. To change $it to have $it.index and $it.item values, add the --numbered (-n) flag. For example:

let names = [Mark Tami Amanda Jeremy]
echo $names | each { build-string "Hello, " $it "!" }
# Outputs "Hello, Mark!" and three more similar lines.

echo $names | each -n { build-string ($it.index | inc) ")" $it.item }

The split row command creates a list from a string based on a delimiter. For example, let colors = (echo "red,green,blue" | split row ",") creates the list [red green blue].

To access a list item at a given index, use $name.index where $name is a variable that holds a list. For example, the second element in the list above which is "Tami" can be accessed with $names.1.

The length command returns the number of items in a list. For example, echo [red green blue] | length outputs 3.

The empty? command determines whether a string, list, or table is empty. It can be used with lists as follows:

= $colors | empty? # false

let colors = []
= $colors | empty? # true

The in and not in operators are used to test whether a value is in a list. Operators can only be used in "math mode". One way to enter math mode is to begin an expression with =. For example:

let colors = [red green blue]
= blue in $colors # true
= yellow in $colors # false

The where command can be used to create a subset of a list. The following example gets all the colors whose names end in "e".

let colors = [red orange yellow green blue purple]
echo $colors | where (echo $it | str ends-with 'e')
# The block passed to where must evaluate to a boolean.
# This outputs the list [orange blue purple].

let scores = [7 10 8 6 7]
echo $scores | where $it > 7 # [10 8]

The any? command determines if any item in a list matches a given condition. For example:

# Do any color names end with "e"?
echo $colors | any? (echo $it | str ends-with "e") # true

# Is the length of any color name less than 3?
echo $colors | any? (echo $it | str length) < 3 # false

# Are any scores greater than 7?
echo $scores | any? $it > 7 # true

# Are any scores odd?
echo $scores | any? $it mod 2 == 1 # true

The all? command determines if every item in a list matches a given condition. For example:

# Do all color names end with "e"?
echo $colors | all? (echo $it | str ends-with "e") # false

# Is the length of all color names greater than or equal to 3?
echo $colors | all? (echo $it | str length) >= 3 # true

# Are all scores greater than 7?
echo $scores | all? $it > 7 # false

# Are all scores even?
echo $scores | all $it mod 2 == 0 # false

The append command appends a single value to the end of a list. The prepend command prepends a single value to the beginning of a list. For example:

let colors = [yellow green]
let colors = (echo $colors | prepend red)
let colors = (echo $colors | append purple)
echo $colors # [red yellow green purple]

The flatten command creates a new list from an existing list by adding items in nested lists to the top-level list. This can be called multiple times to flatten lists nested at any depth. For example:

echo [1 [2 3] 4 [5 6]] | flatten # [1 2 3 4 5 6]

echo [[1 2] [3 [4 5 [6 7 8]]]] |
flatten | flatten | flatten # [1 2 3 4 5 6 7 8]

The reduce command computes a single value from a list. It takes a block which can use the special variables $acc (for accumulator) and $it (for item). To specify an initial value for $acc, use the --fold (-f) flag. To change $it to have $it.index and $it.item values, add the --numbered (-n) flag. This also changes $acc to have a $acc.item value. For example:

let scores = [3 8 4]
echo "total =" (echo $scores | reduce { = $acc + $it }) # 15

echo "total =" (echo $scores | math sum) # easier approach, same result

echo "product =" (echo $scores | reduce --fold 1 { = $acc * $it }) # 96

echo $scores | reduce -n { = $acc.item + $it.index * $it.item }
# This should produce 0*3 + 1*8 + 2*4 = 16.
# But see https://github.com/nushell/nushell/issues/3298.

Tables

The literal syntax for creating a table defines each row with a list, starting with the header row which is followed by a semicolon. For example, echo [[Name Score]; [Mark 19] [Tami 21]] outputs the following table:

╭───┬──────┬───────╮
│ # │ Name │ Score │
├───┼──────┼───────┤
│ 0 │ Mark │ 19 │
│ 1 │ Tami │ 21 │
╰───┴──────┴───────╯

SQL-like syntax can be used to retrieve data from a table. For example:

let scores = [[Name Score]; [Mark 19] [Tami 21]]
echo $scores | where Name == 'Tami' | get Score # 21

The use of the where command above is shorthand for the expanded syntax. This uses the special variable $it which holds the result of the previous command or the current iteration value. The previous pipeline can be written as shown below using this syntax. The curly braces after the where command define a block on which it operates. As we have seen, the leading = enters "math mode" which enables use of operators.

echo $scores | where { = $it.Name == 'Tami'} | get Score # 21

Single-row tables can be used like objects in other languages. For example:

let data = [[color flavor]; [yellow vanilla]]
echo $data.color # outputs yellow
echo $data.flavor # outputs vanilla

Nushell is currently very picky about splitting table data over multiple lines. The newlines in the table definition below break it! See issue 3204.

# This way of adding newlines in a table definition is not parsed correctly.
let sports = [
[name players];
[baseball 9]
[basketball 5]
[football 11]
[hockey 6]
]
# This way is parsed correctly.
let sports = [
[name players
]; [baseball 9
] [basketball 5
] [football 11
] [hockey 6]
]
let sport = basketball
let players = (echo $sports | where name == $sport | get players)
echo `The number of active players in is .`

Tables can contain nested tables. Note the placement of newlines in the example below which avoids the parsing issue described above. The to json command is used to generate JSON from a table.

let person = [
[name address]; [
"Mark Volkmann", [
[street city state zip]; [
"123 Some Street" "Somewhere" "MO" 12345
]
]
]
]

echo $person
echo $person | get address
echo $person | to json --pretty 2

Running the code above produces the following result:

╭───┬───────────────┬────────────────╮
│ # │ name │ address │
├───┼───────────────┼────────────────┤
│ 0 │ Mark Volkmann │ [table 1 rows] │
╰───┴───────────────┴────────────────╯

╭───┬─────────────────┬───────────┬───────┬───────╮
│ # │ street │ city │ state │ zip │
├───┼─────────────────┼───────────┼───────┼───────┤
│ 0 │ 123 Some Street │ Somewhere │ MO │ 12345 │
╰───┴─────────────────┴───────────┴───────┴───────╯

{
"address": [
{
"city": "Somewhere",
"state": "MO",
"street": "123 Some Street",
"zip": 12345
}
],
"name": "Mark Volkmann"
}

Operators

Nushell supports the following operators:

OperatorDescription
+add
-subtract
*multiply
/divide
**exponentiation (power)
modmodulo
==equal
!=not equal
<less than
<=less than or equal
>greater than
>=greater than or equal
=~string contains another
!~string does not contain another
invalue in list
not invalue not in list
&&and two Boolean values
||or two Boolean values

Parentheses can be used for grouping to specify evaluation order. Operators can only be used in "math mode". An expression is in math mode if it begins with =. Commands that take a boolean expression, such as where, keep while, keep until, skip while, and skip util, are automatically evaluated in math mode.

For example, let a = 2; let b = 3; = $a * $b outputs 6.

Working with Numbers

Many of the operators listed in the previous section operate on numbers.

The inc command has three uses.

The first use of inc is to return a value that is one higher that the piped in value. For example, echo 2 | inc gives 3. Since variables are immutable, this cannot be used to increment the value in a variable.

The second use of inc is to increment all the int values in a given table column if all the values are of type int. For example, echo [[Name Size]; [Mark 33] [Tami 28]] | inc Size results in a table where the values in the "Size" column are 34 and 29.

The third use of inc is to increment a specify part of a semantic version number that includes major, minor, and patch parts. For example:

echo 1.2.3 | inc -M # increments major resulting in 2.0.0
echo 1.2.3 | inc -m # increments minor resulting in 1.3.0
echo 1.2.3 | inc -p # increments patch resulting in 1.2.4

There is no dec command for decrementing values.

Working with URLs

The fetch command can be used to get data from a URL.

The website JSONPlaceholder provides access to free sample JSON data. The following example gets data about TODOs from this site.

fetch https://jsonplaceholder.typicode.com/todos |
where userId == 5 && completed == $false |
sort-by title | keep 3

This produces output like the following:

╭───┬────────┬─────┬─────────────────────────────────────────┬───────────╮
│ # │ userId │ id │ title │ completed │
├───┼────────┼─────┼─────────────────────────────────────────┼───────────┤
│ 0 │ 5 │ 97 │ dolorum laboriosam eos qui iure aliquam │ false │
│ 1 │ 5 │ 100 │ excepturi a et neque qui expedita vel │ false │
│ 2 │ 5 │ 94 │ facilis modi saepe mollitia │ false │
╰───┴────────┴─────┴─────────────────────────────────────────┴───────────╯

The post command sends an HTTP POST requests to a server and returns the response as a table. The following example simulates creating a TODO using the JSONPlaceholder site and returns the id of the newly created TODO.

let json = '{"title": "get milk", "userId": 5}"'
post https://jsonplaceholder.typicode.com/todos $json

Nushell does not currently provide commands to send PUT, PATCH, or DELETE requests.

Common UNIX Commands

Many common UNIX commands are supported by Nushell. These are implemented in Rust and are very fast. They include:

CommandDescription
caldisplays a calendar for the current month or an entire specified year
cdchanges the current working directory
clearclears the terminal
cpcopies a file or directory
date nowgets the current date (see the other date subcommands)
dugets information about disk usage
echooutputs the values of expressions
exitexits the current shell; can specify a status code
helpoutputs help information
historyoutputs command history (last 100 commands)
killkills a process
lslists the contents of the current directory or specified path
mkdirmakes (creates) a directory
mvmoves a file or directory
openopens a file
psoutputs process information
pwdoutputs the present (current) working directory
rmremoves (deletes) a file or directory
sourceexecutes a script file in the current context
whichoutputs the path of an executable OR
information about aliases and custom commands

The change to a subdirectory named "sub", enter cd sub or just sub.

The cp, mv, and rm commands do not currently support the -i flag to prompt for confirmation. However, aliases for these can be defined to use the corresponding commands from the parent shell. For example, alias rm = ^rm -i.

Commands such as ls, ps, and sys output data as a table. When a cell displays [table n rows], that indicates that it contains a nested table. Use the get filter to display them (see examples below).

SQL-like filters such as where, sort-by, and reverse can be used to modify the output. The sort-by command accepts the --insensitive (-i) flag to make the sort case-insensitive and the --reverse (-r) flag to reverse the sort order.

Let's walk through some examples.

# List all the package.json files in and below the current directory
# using a glob pattern.
ls **/package.json

# List Rust files in and below the current directory
# using a glob pattern.
ls **/*.rs

# List files in a tree layout.
ls | tree

# List files in the current directory with a size of 2kb or more,
# sorted on size from largest to smallest.
ls | where type == File && size >= 2kb | sort-by size | reverse
ls | where type == File && size >= 2kb | sort-by -r size # same

# List directories in the current directory,
# sorted on size from largest to smallest,
# excluding the type column since all will be "Dir".
ls | where type == Dir | sort-by -r size | reject type

# Output processes using more than 5% of a CPU
# sorted on CPU usage in reverse order.
ps | where cpu > 5 | sort-by -r cpu

# Output information about the current machine
# including OS version, host name, and uptime.
sys | get host

# Output the temperature of the CPUs, GPU, and battery (tested on macOS).
sys | get temp

# Output the parts of the current date and time in a table.
date now | date to-table

To convert a table to a specific text format, use the to command. Supported formats include csv (comma-separated), html, json, md (Markdown), toml, tsv (tab-separated), url (url-encoded text), xml, and yaml. For example, to generate JSON from the ls command output, enter ls | to json.

The save command writes the string output of a command to a file. This is alternative to the > redirect operator used in the Bash shell. The to command can be used to convert non-string data to a string.

For example:

# Create an HTML file describing the directories
# in the current directory that are larger than 1 KB.
ls | where type == Dir && size > 1024 | sort-by -r size | to html |
save big-dirs.html

# The text format defaults to CSV if the file extension is .csv.
# It does not do this for any other file extensions.
ls | where type == Dir && size > 1024 | sort-by -r size | save big-dirs.csv

We can compute the combined size of all the executables installed using the Rust cargo command in the default location. This includes the nu executable and plugins.

ls (build-string (which nu | get path) '*') | get size | math sum

Aliases

To create an alias for a command, enter alias {name} = {command}. For example, alias cls = clear.

The command can be a built-in command or a custom command, and literal arguments can be specified. When aliases are used, additional arguments can be specified. For example:

alias df = date format
date now | df "%B %-d, %Y" # April 3, 2021

To make aliases available in each new Nushell session, add them to the startup list in the config file as shown in the "Configuration" section.

Aliases cannot use pipelines. Custom commands must be used instead. For example, the following does not work:

alias top = ps | sort-by -r cpu | first 10

But defining it as as custom command as follows does work:

def top [] { ps | sort-by cpu -r | first 10 }

Custom Commands

To define a custom command, enter def {name} [params] { commands }. Names can be in kebab-case, including hyphens for readability. They can end with ? to indicate that they return a Boolean value. Square brackets are used to surround the parameters because they are treated as a list and that syntax is used for lists. If no parameters are required, [] must still be included.

The result of a custom command is the result of the last command pipeline or a string formed by the accumulation of everything it echoes.

The following custom command has no parameters and outputs a table showing the processes that have CPU usage of 5% or more sorted from highest to lowest.

def top [] { ps | where cpu >= 5 | sort-by -r cpu }

To run this, enter top.

Here is a version that has a CPU percentage parameter. Parameter values are accessed by adding $ before their names.

def topn [pct] { ps | where cpu >= $pct | sort-by -r cpu }

To run this enter top followed by a number. For example, top 5.

To make custom commands available in each new Nushell session, add them to the startup list in the config file as shown in the "Configuration" section.

The type of each parameter can optionally be specified after a colon to provide better documentation and better error messages when used incorrectly. See the list of "real types" described in the "Data Types" section. For example:

def sum [n1: number, n2: number] { = $n1 + $n2 }

def topn [pct: number] { ps | where cpu >= $pct | sort-by -r cpu }

When invoking a command, multiple arguments are separated by spaces. For example, entering sum 1 2 which outputs 3.

Here are examples of custom commands whose result is defined by what they echo rather than the result of a command pipeline.

def evaluate [n: int] {
echo (build-string "The number " $n " is ")
if $n > 5 { echo big } { echo small }
echo "."
echo (char newline)
}

echo (evaluate 1) # The number 1 is small.
echo (evaluate 9) # The number 9 is big.

def evaluate2 [n: int] {
let word = (if $n > 5 { echo big } { echo small })
echo (build-string "The number " $n " is " $word "." (char newline))
}

echo (evaluate2 1) # The number 1 is small.
echo (evaluate2 9) # The number 9 is big.

Input from other commands can be piped into a custom command and accessed with the $it special variable. Output from custom commands can be piped into other commands.

The parameters in the examples above are positional. Named parameters (a.k.a. flags) can also be specified by adding -- before their names. These are long-form names. To also specify short-form names, follow the long name with (-short-name). Like positional parameters, types can be specified for flags. For example:

# Prints a value followed by a newline.
def logv [value: any] {
echo (build-string $value (char newline))
# Another way to write the line above is:
# echo [`{{$value}}` (char newline)] | str collect
}

# Prints "name = value" followed by a newline.
def lognv [name: string, value: any] {
logv (build-string $name " = " $value)
}

def logv-color [
text: string,
--color (-c): string # a flag
] {
#if (echo $color | empty?) { # same as next line
if ($color | empty?) {
logv $text
} {
logv (build-string (ansi $color) $text (ansi reset))
}
}

logv-color "Giraffes are cool!" -c "yellow"

Custom commands can take arguments with a type of block. The do command can be used to execute the block. For example, this can be used to implement a map command which takes a list and a block.

def map [values: any, code: block] {
echo $values | each $code
}

let names = [Mark Tami Amanda Jeremy]

map $names {
echo (build-string "Hello, " $it (char newline))
} | str collect

# Same result using built-in "each" command instead of custom "map" command.
echo $names | each {
echo (build-string "Hello, " $it ((char newline))
} | str collect

Custom commands can take a variable number of arguments using the parameter syntax ...rest. The parameter name must be "rest" and it must be the last parameter. Its value is a list. For example:

def labelled-sum [label: string, ...rest: int] {
echo (build-string $label " = " (echo $rest | math sum) (char newline))
}

labelled-sum "sum of scores" 3 7 19 # sum of scores = 29

Help for custom commands is obtained in the same way it is for built-in commands, using help {command-name} or {command-name} -h.

To add documentation to custom commands, add a comment before the definition and after each parameter. For example:

# Computes the sum of two numbers.
def sum [
n1: number, # first number
n2: number # second number
] {
= $n1 + $n2
}

Defining a custom subcommand is similar to defining a custom command, but the name is specified as the parent command name and the subcommand name separated by a space and inside quotes. In the following custom commands, the parent command rmv is my initials:

# Parent command.
def rmv [] {}

# Increments a number by 1.
def "rmv increment" [n: number] { = $n + 1 }

# Doubles a number.
def "rmv double" [n: number] { = $n * 2 }

let score = 3
# The "lognv" command is defined above.
lognv 'score' (rmv double (rmv increment $score)) # 8

Variables

Variables in Nushell are distinct from environment variables. They are immutable, so they must be set when they are declared. However, they can be shadowed to have different values in different scopes.

To set a variable, enter let name = value. The scope of a variable is the context or block in which it is defined.

To set a variable to the result of a command pipeline, which can be comprised of one or more commands, enter let name = (pipeline).

To use a variable in an expression, precede its name with $. For example, $total.

The build-str command concatenates the values of multiple expressions into a single string. For example, the following sets a variable to the result of concatenating two variable values as strings:

let v3 = (build-str $v1 $v2)

Environment Variables

Environment variables are distinct from regular variables. Unlike regular variables, environment variables can be accessed by executables that are run from Nushell.

To set the value of an environment variable only in the current scope, not permanently, enter let-env NAME = value. This adds NAME to $nu.env which holds a map of environment variables.

To set the value of an environment variable so it is available in subsequent Nushell sessions, add it to the env section of the Nushell configuration file as shown in the "Configuration" section.

To get the value of an environment variable, use $nu.env.NAME. To print the value, enter
echo $nu.env.NAME or config | get env.{name}.

To see a nicely formatted list of environment variables, enter
echo $nu.env | pivot or config | get env | pivot.

open Command

The open command renders certain file types as tables. These file types include csv, ini, json, toml, xml, and yaml.

Consider the file scores.csv containing the follow:

Name,Score
Mark,19
Tami,21
Amanda,17
Jeremy,15

The command open scores.csv renders this as follows:

╭───┬────────┬───────╮
│ # │ Name │ Score │
├───┼────────┼───────┤
│ 0 │ Mark │ 19 │
│ 1 │ Tami │ 21 │
│ 2 │ Amanda │ 17 │
│ 3 │ Jeremy │ 15 │
╰───┴────────┴───────╯

When run on a JSON file, the open command produces a table from which specific data can be extracted. For example, the following outputs a table of scripts in a package.json file.

open package.json | get scripts | pivot

The output will be similar to the following:

╭───┬─────────┬────────────────────────────────╮
│ # │ Column0 │ Column1 │
├───┼─────────┼────────────────────────────────┤
│ 0 │ dev │ svelte-kit dev │
│ 1 │ build │ svelte-kit build │
│ 2 │ start │ svelte-kit start │
│ 3 │ lint │ prettier --check . && eslint . │
│ 4 │ format │ prettier --write . │
│ 5 │ open │ svelte-kit dev --open │
╰───┴─────────┴────────────────────────────────╯

There is no way to output a table without the heading row. The "#" column can be suppressed from all table output by setting the disable_table_indexes configuration option to true, but there is no way to do this for the output of a specific command.

To see the commands in the Nushell configuration file startup section, enter
open (config path) | get startup.

The lines and split commands can be used to render delimited data as a table. For example, consider the following file content:

Go|2012|Rob Pike
Java|1995|James Gosling
JavaScript|1995|Brendan Eich
Python|1991|Guido van Rossum
Ruby|1995|Yukihiro Matsumoto
Rust|2010|Graydon Hoare
TypeScript|2012|Anders Hejlsberg

The following command renders a table where each row describes a programming language, the columns have proper names, and the rows are sorted on ascending year of creation:

open languages.txt | lines | split column '|' Language Year Creator |
sort-by Year

The lines command converts input text into a list of separate lines from the text. The command above produces the following output.

╭───┬────────────┬──────┬────────────────────╮
│ # │ Language │ Year │ Creator │
├───┼────────────┼──────┼────────────────────┤
│ 0 │ Python │ 1991 │ Guido van Rossum │
│ 1 │ Java │ 1995 │ James Gosling │
│ 2 │ JavaScript │ 1995 │ Brendan Eich │
│ 3 │ Ruby │ 1995 │ Yukihiro Matsumoto │
│ 4 │ Rust │ 2010 │ Graydon Hoare │
│ 5 │ Go │ 2012 │ Rob Pike │
│ 6 │ TypeScript │ 2012 │ Anders Hejlsberg │
╰───┴────────────┴──────┴────────────────────╯

The open command treats other types of files as a list of lines and produces a table where the first column contains line numbers. For known programming language file extensions, the open command uses the bat crate which provides syntax highlighting. Compare this to using the cat command where this does not happen.

If the file extension on a file does not match its content type, use the from command to specify the actual content type. For example, open really-json.txt | from json.

To prevent the open command from processing a file, add the --raw flag. For example, open scores.csv --raw outputs the following:

───────┬────────────
│ scores.csv
───────┼────────────
1 │ Name,Score
2 │ Mark,19
3 │ Tami,21
4 │ Amanda,17
5 │ Jeremy,15
───────┴───────────

To process data from a URL instead of a local file, use the fetch command. For example, the {JSON} Placeholder site provides free data for testing and prototyping. Todo data from this site can be rendered as a table with the following commands:

fetch https://jsonplaceholder.typicode.com/todos | first 10

fetch https://jsonplaceholder.typicode.com/todos |
where userId == 2 && completed == $true | sort-by title

Table Commands

The many Nushell commands that operate on tables are summarized in the table below. Examples of using many of them appear in the sub-sections that follow.

TODO: Add more commands here that have been added.

CommandDescription
all?determines if any row in a table matches a given condition
any?determines if all rows in a table match a given condition
appendcreates a new table by appending a single row to an existing table
compactremoves empty rows
drop nremoves the last n rows (n defaults to 1)
drop column nremoves the last n columns (n defaults to 1)
eachruns a block of code on each row
empty?determines if a table contains no rows
every nshows (default) or skips (with -s option) every nth row
first nshows only the first n rows (n defaults to 1); alternative to keep
flattenflattens a table or list, turning nested values into top-level values
formatformats specified columns into a single string using a pattern
from {format}parses a given file format into a table
get {column-name}gets the content of a given column
group-bycreates multiple tables from one based on some grouping
headerscreates a table from an existing one where the first row replaces the current column headers
histogramcreates a table with "value", "count", "percentage", and "frequency"
columns based on a given column in an input table
insertinserts a column
keep nkeeps the first n rows (n defaults to 1); alternative to first
keep until {condition}keeps rows until the condition is met
keep while {condition}keeps rows while the condition is met
last nshows only the last n rows (n defaults to 1)
lengthcounts rows or list items
matchfilters rows by matching the values in given column against a regular expression
mergecreates a new table by merging the columns of existing tables
movemoves columns to another position
nthkeeps or skips specified rows
parsecreates a single-row table by parsing columns from a string according to a pattern
pivotswaps the rows and columns of a table
prependprepends a row to a table
rangegets a subset of rows
rejectremoves columns by name
renamerenames columns
reversereverses the order of the rows
roll nrolls the bottom n rows to the top (n defaults to 1)
rotaterotates the table 90 degrees clockwise; can apply multiple times
rotate counter-clockwiserotates the table 90 degrees counter-clockwise
select {column-names}specifies columns to be retained by name and their order
shuffleshuffles the rows randomly
skip nskips the first n rows (n defaults to 1)
skip until {condition}skips rows until the condition is met
skip while {condition}skips rows while the condition is met
sort-bysorts rows on given columns
split columncreates a table from a string based on a delimiter
split-bycreates a new table from one with nested tables
where column headings are values of a given nested table heading
tableviews pipeline output as a table
to {format}converts a table to a given format such as JSON
uniqgets unique rows; has duplicated and ignore-case options
updateupdates data in a given column
wherespecifies a condition rows must meet to render
wrapcreates a table column from its data and a name

Let's look at some examples using the ls command. This produces a table with the columns "name", "type", "size", and "modified". Here is a command that lists the files in the current directory with a .ts file extension, only includes the "name" and "size" columns, sorts the files from largest to smallest, and only outputs the three largest files:

ls *.ts | select name size | sort-by -r size | first 3

This produces output similar to the following:

╭───┬────────────────────────┬──────────╮
│ # │ name │ size │
├───┼────────────────────────┼──────────┤
│ 0 │ lib.deno.unstable.d.ts │ 194.4 KB │
│ 1 │ lib.deno.d.ts │ 145.8 KB │
│ 2 │ my_server.ts │ 2.7 KB │
╰───┴────────────────────────┴──────────╯

The row indexes in the first column can be used to retrieve only a specific row using the nth command. For example, adding | nth 1 to the end of the command causes it to only output the row for the file lib.deno.d.ts.

The following sub-sections provide more detail on some of the table commands described above.

all? command

The all? command determines if every row in a table matches a given condition. For example:

# Are all files in the current directory larger than 1 megabyte.
ls | all? size > 1mb # true or false

any? command

The any? command determines if any row in a table matches a given condition. For example:

# Are any files in the current directory larger than 1 megabyte.
ls | any? size > 1mb # true or false

Are all scores even?

echo $scores | all $it mod 2 == 0 # false


### `append` Command

The `append` command creates a new table by
appending a single row to an existing table.
For example:

```bash
let primaryColors = [[name red green blue]; [
  red 255 0 0] [
  green 0 255 0] [
  blue 0 0 255]
]
let purple = [[name red green blue]; [purple 255 0 255]]
let colors = (echo $primaryColors | append $purple)
echo $colors

This produces the following output:

╭───┬────────┬─────┬───────┬──────╮
│ # │ name │ red │ green │ blue │
├───┼────────┼─────┼───────┼──────┤
│ 0 │ red │ 255 │ 0 │ 0 │
│ 1 │ green │ 0 │ 255 │ 0 │
│ 2 │ blue │ 0 │ 0 │ 255 │
│ 3 │ purple │ 255 │ 0 │ 255 │
╰───┴────────┴─────┴───────┴──────╯

each Command

The each command runs a block of code on each row of a table. For example:

ls *.nu | each {
let name = (echo $it | get name)
let size = (echo $it | get size)
echo (build-string $name ' is ' $size '.')
} | as-lines

This produces output like the following:

append-demo.nu is 670 B.
block-param.nu is 305 B.
chart-demo.nu is 189 B.

empty? command

The empty? command determines whether a string, list, or table is empty. It can be used with tables as follows:

let scores = [[Name Score]; [Mark 19] [Tami 21]]
= $scores | empty? # false

let scores = []
= $scores | empty? # true; not empty if only header row is present

flatten Command

The flatten command operates on both lists and tables. It can create a new table from an existing table, replacing columns that whose values are nested tables with the columns in those tables. For example, the sys command creates a table with the columns "host", "cpu", "disks", "mem" (for memory), "temp" (for temperature), and "net" (for network activity). Piping this output to the flatten command replaces the "host" and "mem" columns with the columns in their nested tables.

format Command

The format command formats specified columns into a single string using a pattern. For example:

ls | format '{name} is a {size} {type} and was modified {modified}.' |
str downcase
# downcase is used to change the type to lowercase.

This outputs lines like the following:

histogram.nu is a 233 b file and was modified 1 week ago.

from Command

The from command parses a given file format into a table. For example:

let data = (open --raw scores.csv)
let table = echo $data | from csv

This can be done in a single line with let table = (open scores.csv).

TODO: How could you iterate over the rows of a table and add each one to another table? Use reduce and append? See append-demo.nu.

get Command

The get command can be used to output only the values in a single column. It returns a list rather than a table. For example, the following outputs the names of the three largest TypeScript files in the current directory:

ls *.ts | sort-by size | reverse | first 3 | get name

The get command is especially useful when the type of a field is "table". The key can be arbitrarily deep with sub-keys separated by periods. For example, sys | get host.sessions | where name == 'root' | get groups.

The following example demonstrates getting all the headings from a table.

echo $myTable | get

Table columns can be accessed by their header name using the get and select commands, but there is no command to get a table column by its index. However, this can be done with the following pipeline:

echo $myTable | select (echo $myTable | get | nth $columnIndex)

group-by Command

The rows of a table can be segregated into multiple tables using the group-by command. For example, the output of ls can be split into two tables where one contains rows with a type of "File" and the other contains rows with a type of "Dir". The following command produces a table with the columns "File" and "Dir" that contains a single row whose cells are themselves tables.

ls | group-by type

The following code outputs the nested tables:

let temp = (ls | group-by type)
echo $temp | get File
echo $temp | get Dir

The group-by command can be passed a block that computes the value used to group the rows. The following example groups files based on their file extension:

ls | group-by { get name | path extension }

To see the contents of one of the nested tables, pipe this to get ext-name.

Another way to see only the files whose name ends with certain characters is the use the where command with a block as follows:

ls | where {= (echo $it.name | str ends-with ".rs") } | get name

histogram Command

The histogram command generates a histogram from the data in a given table row. For example:

# The newlines need to be placed like this
# due to a parser bug.
let data = [
[name color]; [
Mark yellow] [
Tami blue] [
Amanda green] [
Jeremy yellow] [
Sally blue] [
Sam yellow]
]
echo $data | get color | histogram

This produces the following table:

╭───┬────────┬───────┬────────────┬──────────────────────────────────────────╮
│ # │ value │ count │ percentage │ frequency │
├───┼────────┼───────┼────────────┼──────────────────────────────────────────┤
│ 0 │ blue │ 2 │ 66.67% │ ************************** │
│ 1 │ green │ 1 │ 33.33% │ ************* │
│ 2 │ yellow │ 3 │ 100.00% │ **************************************** │
╰───┴────────┴───────┴────────────┴──────────────────────────────────────────╯

The percentage values are double what you might expect. This is because the value when the largest count is assigned a percentage of 100 and all the other percentages are calculated relative to that count. See issue 3215.

split and headers Commands

The table in the previous example can be created from a string using the split and headers commands.

let data =
"name red green blue|red 255 0 0|green 0 255 0|blue 0 0 255|purple 255 0 255"
let colors = (echo $data | split row "|" | split column " " | headers)
echo $colors

The split-by command doesn't seem very useful.

TODO: See split-by-demo.nu.

match Command

The match command filters rows by matching the values in given column against a regular expression. For example, ls | where type == File | match name "^c.*\.nu$" lists files in the current directory whose name begin with "c" and have a file extension of ".nu".

merge Command

The merge command creates a new table by merging the columns of existing tables. For example:

let t1 = [[name score]; [Mark 19] [Tami 21]]
echo $t1

# Add a single column.
let column = (echo [yellow blue] | wrap color)
echo $t1 | merge { echo $column }

# Add all the columns from another table.
let t2 = [[color flavor]; [yellow vanilla] [blue chocolate]]
echo $t1 | merge { echo $t2 }

The output produced by this example is:

╭───┬──────┬───────╮
│ # │ name │ score │
├───┼──────┼───────┤
│ 0 │ Mark │ 19 │
│ 1 │ Tami │ 21 │
╰───┴──────┴───────╯

╭───┬──────┬───────┬────────╮
│ # │ name │ score │ color │
├───┼──────┼───────┼────────┤
│ 0 │ Mark │ 19 │ yellow │
│ 1 │ Tami │ 21 │ blue │
╰───┴──────┴───────┴────────╯

╭───┬──────┬───────┬────────┬───────────╮
│ # │ name │ score │ color │ flavor │
├───┼──────┼───────┼────────┼───────────┤
│ 0 │ Mark │ 19 │ yellow │ vanilla │
│ 1 │ Tami │ 21 │ blue │ chocolate │
╰───┴──────┴───────┴────────┴───────────╯

move Command

The move command moves specified columns to after or before another column. For example, by default the ls command outputs a type with the columns "name", "type", "size", and "modified". The following command moves the "type" and "size" columns to be after the "modified" column. It also reorders the "size" and "type" columns to the specified order.

ls | move size type --after modified

parse Command

The parse command creates a single-row table by parsing columns from a string using a pattern. For example:

echo "123 Some St., St. Charles, MO 63304" |
parse "{street}, {city}, {state} {zip}"

This outputs the following table:

╭───┬──────────────┬─────────────┬───────┬───────╮
│ # │ street │ city │ state │ zip │
├───┼──────────────┼─────────────┼───────┼───────┤
│ 0 │ 123 Some St. │ St. Charles │ MO │ 63304 │
╰───┴──────────────┴─────────────┴───────┴───────╯

pivot Command

The pivot command swaps the rows and columns of a table. For example,
ls *.nu | sort-by -r size | first 3 | pivot
produces output like the following:

╭───┬──────────┬────────────┬──────────────────┬────────────────╮
│ # │ Column0 │ Column1 │ Column2 │ Column3 │
├───┼──────────┼────────────┼──────────────────┼────────────────┤
│ 0 │ name │ rmv.nu │ split-by-demo.nu │ append-demo.nu │
│ 1 │ type │ File │ File │ File │
│ 2 │ size │ 1.3 KB │ 927 B │ 670 B │
│ 3 │ modified │ 1 week ago │ 1 week ago │ 4 days ago │
╰───┴──────────┴────────────┴──────────────────┴────────────────╯

prepend Command

The prepend command creates a new table by prepending a single row to an existing table. For example:

let primaryColors = [[name red green blue]; [
red 255 0 0] [
green 0 255 0] [
blue 0 0 255]
]
let white = [[name red green blue]; [white 255 255 255]]
let colors = (echo $primaryColors | prepend $white)
echo $colors

This does not currently produce the expected output, but piping the output to the flatten command fixes it. See issue 3269.

split column Command

The split column command creates a table from a string based on a delimiter. For example, echo "red,green,blue" | split column "," produces the following output:

╭───┬─────────┬─────────┬─────────╮
│ # │ Column1 │ Column2 │ Column3 │
├───┼─────────┼─────────┼─────────┤
│ 0 │ red │ green │ blue │
╰───┴─────────┴─────────┴─────────╯

to Command

The to command converts a table to a given format such as JSON. It is followed by a format name which can be one of the following: csv, html, json, md, toml, tsv, url, xml, and yaml. The toml, url, and xml formats are only applicable on tables that meet specific requirements. For example:

let scores = [[Name Score]; [Mark 19] [Tami 21]]
echo $scores | to csv
echo $scores | to json
echo $scores | to md
echo $scores | to yaml

This produces the following output:

Name,Score
Mark,19
Tami,21

[{"Name":"Mark","Score":19},{"Name":"Tami","Score":21}]

|Name|Score|
|-|-|
|Mark|19|
|Tami|21|

---
- Name: Mark
Score: 19
- Name: Tami
Score: 21

Plugins

Nushell plugins add new commands. Supported plugins can be found in the crates directory of the Nushell GitHub repository. Look for subdirectories whose names being with "nu_plugin_". All of these are installed by default if Nushell is installed using the command cargo install nu --features=extra.

Additional plugins can be installed using the Rust cargo utility. Specify the directories where these plugins are installed in the configuration setting plugin_dirs which is a list of directories where Nushell should search for plugins. After installing plugins and changing this setting, open a new shell to gain access to the commands that they add.

The following sub-sections describe some commonly used plugins.

nu_plugin_start

This plugin adds the start command that opens a given file using its default application. For example, start demo.html will open the HTML file in the default web browser.

nu_plugin_chart

This plugin adds the chart command with the subcommands bar and line.

Here is an example of creating both kinds of charts.

let data = [[name score]; [
Mark 19] [
Tami 21] [
Amanda 17] [
Jeremy 15]
]

echo $data | chart bar [name score]
echo $data | chart line [name score]

After each chart is rendered, press enter to go to the next chart or exit if the last chart has been rendered.

Unfortunately these plot the frequencies of the values and not values themselves. So the bar chart shows four bars at 100% because the values 19, 21, 17, and 15 each occur once. See issue 3096.

Default Shell

To make Nushell your default shell in Linux or macOS, first add a line containing the file path to the nu executable in /etc/shells. For example, using macOS I entered su vim /etc/shells and added the line /Users/mark/.cargo/bin/nu. Then change the default shell by entering chsh -s nu. If using tmux, also change the value of default-shell in ~/.tmux.conf.

Scripts

Nushell scripts are written in files with a .nu extension. To execute a script, enter nu {name}.nu. To "source" a script so its definitions become available in the current shell, enter source {name}.nu.

For examples of Nushell scripts, see Nu_101 Scripts.

To add comments or comment-out a line of code, begin the comment with a # character.

Commands commonly used in Nushell scripts include def, if, each, and seq.

As we saw in the "Custom Commands" section, the def command defines a custom command that can be used like a function in many programming languages.

Conditional processing is implemented with the if command. Its syntax is if condition { then-block } { else-block }. Note that the condition is not surrounded by parentheses and curly braces are required around the then and else blocks. There are no then or else keywords. Nested ifs must be placed inside a then or else block. An if command can be split over multiple lines. For example:

let temperature = 80
if $temperature <= 32 {
echo cold
} {
if $temperature >= 80 {
echo hot
} {
echo warm
}
}

To iterate over a range of integers, use the seq command and pipe the result to the each command. The special variable $it holds each iteration value. For example:

seq 1 4 | each { build-string $it (char newline) } | str collect

Let's break this down.

The seq command creates a list of strings, not integers. An alternative is to use the echo command with a range specified with start..end which creates a list of integers. The previous example can also be written as follows:

echo 1..4 | each { build-string $it (char newline) } | str collect

Iteration over the elements of a list is implemented with the each command. Its syntax is echo some-list | each { block }. The block can use the special variable $it to access the current item in the iteration. For example:

def log-value [label, value] {
echo (build-string $label " = " $value (char newline))
}

def report [list] {
# Without the --numbered flag, $it is set to each list value.
# With it, $it is set to an object with the properties index and item.
echo $list | each --numbered {
build-string ($it.index + 1) ") " $it.item (char newline)
} | str collect # with this the result is a table instead of a string
}

let names = [Mark Tami Amanda Jeremy]

log-value "name at index 2" (echo $names | nth 2) # Amanda

report $names
# 1) Mark
# 2) Tami
# 3) Amanda
# 4) Jeremy

VS Code

There is a VS Code extension for Nushell that provides syntax highlighting for Nushell scripts. See vscode-nushell-lang.

Comparison to Bash

The following table shows the Nushell equivalent of some common Bash commands.

BashNushellDescription
man commandhelp {command}outputs help for a command;
help commands lists Nushell
commands and custom commands
$PATH$nu.pathholds the list of directories
searched for executables
cat {file-path}open --raw {file-path}prints the contents of a file;
omit --raw to output structured data
command > {file-path}command | save --raw {file-path}saves command output to a file
without converting based on file extension
mkdir -p foo/bar/bazmkdir foo/bar/bazcreates directory structure,
including any missing directories
cmd1 && cmd2cmd1; cmd2runs cmd1 and then only runs
cmd2 if cmd1 was successful

The command whose output is piped in the save command must produce a string. For example,
date now | save --raw timestamp.txt does not work, but
date now | str from | save --raw timestamp.txt does.

Per Directory Environment Variables

Nushell supports defining actions to happen when changing to given directories. To configure this, create a .nu-env file in each directory. These are TOML files with the following sections:

TOML SectionDescription
[env]sets environment variables to literal values;
lines have the syntax name = "value"
[scriptvars]sets environment variables to command output;
lines have the syntax name = "command-pipeline"
[scripts]specifies commands to run when entering and exiting the directory
with entryscripts and exitscripts commands

After creating the .nu-env file in each directory, enter autoenv trust to give Nushell permission to read the file.

For example, suppose we want to set the environment variable NODE_ENV to development or production based on the current directory. Add the following setting in the Nushell configuration file:

nu_env_dirs = [
"~/projects/airline-reservations",
"~/projects/bank-accounts"
]

In the ~/projects/airline-reservations directory, create the file .nu-env containing the following and then enter autoenv trust:

[env]
NODE_ENV = "development"

In the ~/projects/bank-accounts directory, create the file .nu-env containing the following and then enter autoenv trust:

[env]
NODE_ENV = "production"

Now cd to each of these directories and verify that the NODE_ENV environment variable is set to the expected value.

Currently the echo command does not write to stdout when run from entryscripts or exitscripts.

For more details on this feature, enter help autoenv.

Additional Shells

New shells can be created from the current shell. This enables retaining the working directory of the current shell and switching back to it using the n (for next) and p (for previous) commands.

Here is a summary of the commands related to working with multiple shells.

CommandDescription
enter dir-pathsimilar to cd, but creates a new shell starting in the given directory
enter file-pathcreates a new shell whose context is the content of the given file;
seems like an odd feature
shellslists the existing shells and indicates which one is active
nmakes the next shell in the list active;
wrapping to the first if in the last
pmakes the previous shell in the list active;
wrapping to the last if in the first
exitexits the current shell, removing it from the list
exit --nowexits all the shells;
depending on configuration the terminal window may close

Issues