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.
enter
nu -vto see the current versionoptionally update the Rust toolchain if tools may be out of date by entering
rustup updateenter
cargo install nuto install the new version of NushellThis takes a very long time, perhaps 10 minutes. It installs the
nuexecutable in$HOME/.cargo/bin.enter
nuto verify that a new version was installed
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}.
| Subcommand | Description |
|---|---|
basename | returns the filename portion (demo.txt) |
dirname | returns the directory path (~/Documents) |
exists | returns a boolean indicating if the file exists; can only return true for expanded paths |
expand | returns the expanded path (/Users/mark/Documents/demo.txt) |
join | returns the result of joining two partial pathsecho '~/Documents' | path join -a demo.txtreturns ~/Documents/demo.txt |
parse | converts a path to structured data including parent (directory path), stem (filename w/o extension), and extension |
relative-to | returns a path relative to another |
split | returns the parts of a path split by a separator |
type | returns 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:
| Setting | Description |
|---|---|
disable_table_indexes | when true, omits index column from table output |
path | list of directories in quotes to search for executables |
prompt | command whose output is used for the prompt |
skip_welcome_message | when true, starting a shell doesn't output awelcome message including the Nushell version |
startup | list of commands to execute when a shell starts; typically defines aliases and custom commands |
table_mode | controls 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.
| Command | Description |
|---|---|
config | outputs all the settings |
config path | outputs 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:
- basic: uses +, -, and | characters for borders
- compact: omits outer left and right borders
- compact_double: like compact, but uses double lines for borders
- heavy: thicker border on every cell
- light: horizontal line below header and no other borders
- none: no borders
- reinforced: border on every cell with thick table corners
- rounded: border on every cell and rounded table corners (my favorite)
- thin: border on every cell
- with_love: heart characters for borders
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:
| Setting | Description |
|---|---|
edit_mode | "emacs" or "vi"default is to use rustyline key bindings |
history_duplicates | "alwaysadd" or "ignoreconsecutive" (default) |
history_ignore_space | true (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 = truepath 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.
| Setting | Description |
|---|---|
| grid | true (default) or false |
| header | true (default) or false |
| line_numbers | true (default) or false |
| theme | ex. "Coldark-Dark" |
| true_color | true or false |
| vcs_modification_markers | true 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:
| Type | Description |
|---|---|
any | any type below (default for variables and custom command parameters) |
block | block of nu script code (can be executed on each row of a table) |
duration | number followed by a unit which can be ms, sec, min, hr, day, or wk |
filesize | number followed by a unit which can be b, kb, mb, gb, tb, or pb |
int | whole number with infinite precision |
number | int or decimal, both with infinite precision |
path | platform-independent path to a file or directory |
pattern | glob pattern that can include * wildcard and ** for traversing directories |
range | {start}..{end} (inclusive) or {start}..<{end} (end is exclusive); use 2 dots, not 3 |
string | single words need no delimiter; multiple words need single quotes, double quotes, or backticks |
table | list 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:
| Type | Description |
|---|---|
| binary | sequence of raw bytes |
| boolean | literal values are $true and $false |
| column path | dot-separated list of nested column names |
| date | timezone-aware; defaults to UTC |
| decimal | number with a fractional part and infinite precision |
| group | semicolon-separated list of pipelines where only output from the last is output |
| line | string with an OS-dependent line ending |
| list | sequence of values of any type |
| row | list 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?
| From | To | Command |
|---|---|---|
any | string | pipe to describe |
| boolean | string | pipe to str from |
| date | string | pipe to str from |
int | string | pipe to str from |
| list | string | pipe to str collect if the list contains strings |
number | string | pipe to str from |
path | string | pipe to ??? |
pattern | string | pipe to ??? |
range | string | pipe to ??? |
table | string | pipe to ??? |
unit | string | pipe to str from * |
string | boolean | pipe to ??? |
string | date | pipe to str to-datetime |
string | int | pipe to str to-int |
string | list | pipe to split row |
string | number | pipe to str to-decimal |
string | path | pipe to ??? |
string | range | pipe to ??? |
string | table | pipe to ??? |
string | unit | pipe 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? # trueThe operators =~ and !~ test whether one string contains or does not contain another.
For example:
= "foobarbaz" =~ "bar" # true
= "foobarbaz" !~ "bar" # falseThe 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 linesTypes 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? # trueThe 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 # falseThe 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 # trueThe 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 # falseThe 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 # 21The 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 # 21Single-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 vanillaNushell 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 2Running 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:
| Operator | Description |
|---|---|
+ | add |
- | subtract |
* | multiply |
/ | divide |
** | exponentiation (power) |
mod | modulo |
== | equal |
!= | not equal |
< | less than |
<= | less than or equal |
> | greater than |
>= | greater than or equal |
=~ | string contains another |
!~ | string does not contain another |
in | value in list |
not in | value 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.4There 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 3This 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 $jsonNushell 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:
| Command | Description |
|---|---|
cal | displays a calendar for the current month or an entire specified year |
cd | changes the current working directory |
clear | clears the terminal |
cp | copies a file or directory |
date now | gets the current date (see the other date subcommands) |
du | gets information about disk usage |
echo | outputs the values of expressions |
exit | exits the current shell; can specify a status code |
help | outputs help information |
history | outputs command history (last 100 commands) |
kill | kills a process |
ls | lists the contents of the current directory or specified path |
mkdir | makes (creates) a directory |
mv | moves a file or directory |
open | opens a file |
ps | outputs process information |
pwd | outputs the present (current) working directory |
rm | removes (deletes) a file or directory |
source | executes a script file in the current context |
which | outputs 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-tableTo 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.csvWe 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 sumAliases
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, 2021To 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 10But 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 collectCustom 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 = 29Help 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)) # 8Variables
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, enterecho $nu.env.NAME or config | get env.{name}.
To see a nicely formatted list of environment variables, enterecho $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,15The 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 | pivotThe 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, enteropen (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 HejlsbergThe 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 YearThe 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 titleTable 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.
| Command | Description |
|---|---|
all? | determines if any row in a table matches a given condition |
any? | determines if all rows in a table match a given condition |
append | creates a new table by appending a single row to an existing table |
compact | removes empty rows |
drop n | removes the last n rows (n defaults to 1) |
drop column n | removes the last n columns (n defaults to 1) |
each | runs a block of code on each row |
empty? | determines if a table contains no rows |
every n | shows (default) or skips (with -s option) every nth row |
first n | shows only the first n rows (n defaults to 1); alternative to keep |
flatten | flattens a table or list, turning nested values into top-level values |
format | formats 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-by | creates multiple tables from one based on some grouping |
headers | creates a table from an existing one where the first row replaces the current column headers |
histogram | creates a table with "value", "count", "percentage", and "frequency" columns based on a given column in an input table |
insert | inserts a column |
keep n | keeps 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 n | shows only the last n rows (n defaults to 1) |
length | counts rows or list items |
match | filters rows by matching the values in given column against a regular expression |
merge | creates a new table by merging the columns of existing tables |
move | moves columns to another position |
nth | keeps or skips specified rows |
parse | creates a single-row table by parsing columns from a string according to a pattern |
pivot | swaps the rows and columns of a table |
prepend | prepends a row to a table |
range | gets a subset of rows |
reject | removes columns by name |
rename | renames columns |
reverse | reverses the order of the rows |
roll n | rolls the bottom n rows to the top (n defaults to 1) |
rotate | rotates the table 90 degrees clockwise; can apply multiple times |
rotate counter-clockwise | rotates the table 90 degrees counter-clockwise |
select {column-names} | specifies columns to be retained by name and their order |
shuffle | shuffles the rows randomly |
skip n | skips 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-by | sorts rows on given columns |
split column | creates a table from a string based on a delimiter |
split-by | creates a new table from one with nested tables where column headings are values of a given nested table heading |
table | views pipeline output as a table |
to {format} | converts a table to a given format such as JSON |
uniq | gets unique rows; has duplicated and ignore-case options |
update | updates data in a given column |
where | specifies a condition rows must meet to render |
wrap | creates 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 3This 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 falseany? 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 falseAre 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-linesThis 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 presentflatten 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 csvThis 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 nameThe 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 | getTable 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 typeThe following code outputs the nested tables:
let temp = (ls | group-by type)
echo $temp | get File
echo $temp | get DirThe 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 namehistogram 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 | histogramThis 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 $colorsThe 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 modifiedparse 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 $colorsThis 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 yamlThis 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: 21Plugins
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 collectLet's break this down.
seq 1 4returns the list[1 2 3 4].each { build-string $it (char newline) }returns the list["1\n" "2\n" "3\n" "4\n"]str collectreturns a string created by concatenating the list values.The output is:
1
2
3
4
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 collectIteration 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) JeremyVS 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.
| Bash | Nushell | Description |
|---|---|---|
man command | help {command} | outputs help for a command;help commands lists Nushellcommands and custom commands |
$PATH | $nu.path | holds 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/baz | mkdir foo/bar/baz | creates directory structure, including any missing directories |
| cmd1 && cmd2 | cmd1; cmd2 | runs 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, butdate 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 Section | Description |
|---|---|
[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.
| Command | Description |
|---|---|
enter dir-path | similar to cd, but creates a new shell starting in the given directory |
enter file-path | creates a new shell whose context is the content of the given file; seems like an odd feature |
shells | lists the existing shells and indicates which one is active |
n | makes the next shell in the list active; wrapping to the first if in the last |
p | makes the previous shell in the list active; wrapping to the last if in the first |
exit | exits the current shell, removing it from the list |
exit --now | exits all the shells; depending on configuration the terminal window may close |
Issues
- Fuzzy completion is not yet supported. For example, entering
cd fooand pressing the tab key completes to names that begin withfoo, but not names that merely containfoo. - The literal syntax for tables is currently very picky about the location of newline characters due to a parser bug. See issue 3204
- Several data types discussed in the official documentation cannot be used as parameter types of custom commands. These include boolean, date, decimal, duration, filesize, and list. Perhaps these will become real types in the future.
- There is no built-in
grepcommand. Consider using ripgrep.