Modern structured-data shell that treats command output as tables and supports pipelines with typed data, filtering, and cross-platform scripting.
| Command | Description |
|---|
brew install nushell | Install on macOS with Homebrew |
cargo install nu | Install from crates.io |
winget install nushell | Install on Windows with winget |
sudo apt install nushell | Install on Debian/Ubuntu |
pacman -S nushell | Install on Arch Linux |
nix-env -i nushell | Install on NixOS |
nu | Launch Nushell |
nu --version | Show installed version |
nu -c "ls" | Run a single command and exit |
nu script.nu | Execute a Nushell script file |
chsh -s /usr/bin/nu | Set Nushell as default shell |
| Command | Description |
|---|
sys | Show full system information |
sys host | Show host details (name, OS, kernel) |
sys mem | Show memory usage |
sys cpu | Show CPU information |
sys disks | Show disk usage |
sys net | Show network interfaces |
sys temp | Show temperature sensors |
date now | Show current date and time |
date now | format date "%Y-%m-%d" | Format current date |
$nu.home-path | Show home directory path |
$nu.os-info | Show OS details |
| Command | Description |
|---|
ls | List files as structured table |
ls -l | Long listing with details |
ls -a | Show hidden files |
ls **/*.rs | Recursive glob for Rust files |
ls | where size > 1mb | Filter files larger than 1MB |
ls | where type == dir | Filter for directories only |
ls | sort-by modified -r | Sort by modification date (newest first) |
ls | sort-by size -r | Sort by size descending |
ls | get name | Get only file names column |
| Command | Description |
|---|
ps | List processes as table |
ps | where cpu > 10 | Find processes using >10% CPU |
ps | where name =~ "node" | Find processes by name pattern |
ps | sort-by mem -r | first 10 | Top 10 processes by memory |
ps | where pid == 1234 | Find process by PID |
| Command | Description |
|---|
help | Show general help |
help commands | List all available commands |
help ls | Show help for specific command |
help operators | List available operators |
help escapes | Show string escape sequences |
| Command | Description |
|---|
ls | select name size | Select specific columns |
ls | reject modified | Remove specific columns |
ls | rename filename filesize | Rename columns |
ls | first 5 | Get first 5 rows |
ls | last 3 | Get last 3 rows |
ls | skip 10 | Skip first 10 rows |
ls | length | Count number of rows |
ls | reverse | Reverse row order |
ls | shuffle | Randomize row order |
ls | flatten | Flatten nested tables |
ls | columns | List column names |
| Command | Description |
|---|
ls | where size > 1mb | Filter by comparison |
ls | where name =~ "test" | Filter by regex match |
ls | where name starts-with "src" | Filter by prefix |
ls | where name ends-with ".md" | Filter by suffix |
ls | where type in ["file" "dir"] | Filter by value list |
ls | sort-by size -r | Sort descending |
ls | sort-by name -i | Sort case-insensitive |
ls | uniq-by type | Remove duplicates by column |
ls | group-by type | Group rows by column value |
| Command | Description |
|---|
ls | each { |it| $it.name } | Transform each row |
ls | par-each { |it| $it.name } | Transform in parallel |
ls | update size { |it| $it.size / 1kb } | Update column values |
ls | insert label { |it| $it.name + "-file" } | Add new column |
ls | reduce -f 0 { |it, acc| $acc + $it.size } | Accumulate values |
ls | enumerate | Add index column |
ls | window 3 | Sliding window of 3 rows |
ls | zip [1 2 3] | Zip with another list |
ls | transpose | Swap rows and columns |
| Command | Description |
|---|
42 | Integer |
3.14 | Float |
"hello" | String |
true / false | Boolean |
null | Null value |
2024-01-15 | Date |
5sec / 3min / 2hr | Duration |
1kb / 5mb / 2gb | File size |
0b1010 | Binary literal |
0xff | Hexadecimal literal |
| Command | Description |
|---|
[1 2 3] | List |
[1 2 3] | append 4 | Append to list |
[1 2 3] | prepend 0 | Prepend to list |
{name: "Alice", age: 30} | Record |
{a: 1} | merge {b: 2} | Merge records |
[[name age]; ["Alice" 30] ["Bob" 25]] | Table literal |
0..9 | Range (0 to 9) |
0..<9 | Exclusive range (0 to 8) |
0..2..10 | Range with step (0, 2, 4, 6, 8, 10) |
| Command | Description |
|---|
"42" | into int | String to integer |
"3.14" | into float | String to float |
42 | into string | Number to string |
"true" | into bool | String to boolean |
"2024-01-15" | into datetime | String to datetime |
1024 | into filesize | Number to filesize |
5 | into duration --unit sec | Number to duration |
42 | into binary | Number to binary |
[1 2 3] | into record | List to record |
{a: 1} | into record | Convert to record |
| Command | Description |
|---|
open data.json | Open and parse JSON file |
open data.csv | Open and parse CSV file |
open data.yaml | Open and parse YAML file |
open data.toml | Open and parse TOML file |
open data.xml | Open and parse XML file |
open data.tsv | Open and parse TSV file |
open data.sqlite | Open SQLite database |
open file.txt | Open as plain text |
open data.json | get users | Open and navigate into data |
| Command | Description |
|---|
"hello" | save hello.txt | Save string to file |
ls | save files.json | Save table as JSON |
ls | save files.csv | Save table as CSV |
ls | save files.yaml | Save table as YAML |
open data.json | to csv | Convert JSON to CSV |
open data.csv | to json | Convert CSV to JSON |
open data.json | save data.yaml | Convert between formats |
open data.csv | save -f data.csv | Force overwrite existing file |
"line1\nline2" | save -a log.txt | Append to file |
| Command | Description |
|---|
open file.txt | lines | Split file into lines |
open file.txt | lines | length | Count lines in file |
open file.csv | where status == "active" | Filter CSV rows |
open file.json | select name email | Pick fields from JSON |
open file.json | to yaml | save file.yaml | Convert JSON to YAML |
glob "**/*.md" | each { |f| open $f } | Open all matching files |
| Command | Description |
|---|
"hello world" | str upcase | Convert to uppercase |
"HELLO" | str downcase | Convert to lowercase |
"hello" | str capitalize | Capitalize first letter |
" hello " | str trim | Trim whitespace |
"hello" | str trim --char "h" | Trim specific character |
"hello" | str reverse | Reverse string |
| Command | Description |
|---|
"hello world" | str replace "world" "nu" | Replace first occurrence |
"aabaa" | str replace -a "a" "x" | Replace all occurrences |
"hello world" | str replace -r '\w+' 'word' | Replace with regex |
"hello world" | str contains "world" | Check if string contains |
"hello world" | str starts-with "hello" | Check prefix |
"hello world" | str ends-with "world" | Check suffix |
"hello world" | str index-of "world" | Find position of substring |
| Command | Description |
|---|
"hello world" | split row " " | Split by delimiter |
"a,b,c" | split row "," | Split CSV-style string |
"hello" | split chars | Split into characters |
["hello" "world"] | str join " " | Join list into string |
["a" "b" "c"] | str join "," | Join with comma |
"hello" | str length | Get string length |
"hello world" | str substring 0..5 | Extract substring |
# Basic interpolation
let name = "World"
$"Hello, ($name)!"
# Expression interpolation
$"Total: (1 + 2 + 3)"
# Multi-line strings
$"Line 1
Line 2
Line 3"
# Raw strings (no escapes)
r#'C:\Users\path'#
| Command | Description |
|---|
def greet [name: string] { $"Hello, ($name)!" } | Basic custom command |
def add [a: int, b: int] -> int { $a + $b } | Command with type annotations |
def greet [name = "World"] { ... } | Command with default parameter |
def "git branches" [] { git branch | lines } | Subcommand-style name |
def --wrapped cmd [...rest] { ... } | Accept any extra arguments |
| Command | Description |
|---|
let x = 42 | Immutable variable |
mut x = 0; $x = $x + 1 | Mutable variable |
const PI = 3.14159 | Compile-time constant |
if $x > 0 { "pos" } else { "neg" } | Conditional expression |
match $x { 1 => "one", 2 => "two", _ => "other" } | Pattern matching |
for item in [1 2 3] { print $item } | For loop |
while $x < 10 { $x = $x + 1 } | While loop |
loop { if $x > 10 { break }; $x += 1 } | Infinite loop with break |
try { risky_op } catch { "failed" } | Error handling |
# Function with flag parameter
def greet [
name: string # Name to greet
--excited (-e) # Use exclamation mark
] {
if $excited {
$"Hello, ($name)!"
} else {
$"Hello, ($name)."
}
}
# Function with rest parameters
def sum [...nums: int] -> int {
$nums | math sum
}
# Pipeline input function
def double-all [] {
each { |x| $x * 2 }
}
# Usage: [1 2 3] | double-all
| Command | Description |
|---|
[1 2 3 4 5] | math sum | Sum of values |
[1 2 3 4 5] | math avg | Average of values |
[1 2 3 4 5] | math min | Minimum value |
[1 2 3 4 5] | math max | Maximum value |
[1 2 3 4 5] | math median | Median value |
[1 2 3 4 5] | math stddev | Standard deviation |
[1 2 3 4 5] | math variance | Variance |
[1 2 3] | math product | Product of values |
10 | math abs | Absolute value |
10 | math sqrt | Square root |
2 | math round -p 2 | Round to precision |
10 | math log 2 | Logarithm base 2 |
| Command | Description |
|---|
http get https://api.example.com/data | GET request |
http post https://api.example.com/data {name: "test"} | POST request with JSON |
http put https://api.example.com/data/1 {name: "updated"} | PUT request |
http delete https://api.example.com/data/1 | DELETE request |
http get url --headers [Accept application/json] | GET with custom headers |
http get url | get data | GET and extract field |
port 8080 | Check if port is in use |
# Fetch and process JSON API
let users = (http get "https://jsonplaceholder.typicode.com/users")
$users | select name email | first 5
# POST with headers and body
http post "https://api.example.com/items" {
name: "New Item"
price: 29.99
} --headers [Authorization $"Bearer ($env.API_TOKEN)"]
| Command | Description |
|---|
$nu.config-path | Show config file path |
$nu.env-path | Show env config file path |
$nu.default-config-dir | Show config directory |
config nu | Open config in editor |
config env | Open env config in editor |
| Command | Description |
|---|
$env.config.show_banner = false | Disable startup banner |
$env.config.buffer_editor = "vim" | Set editor for Ctrl+O |
$env.config.history.file_format = "sqlite" | Use SQLite history |
$env.config.history.max_size = 100_000 | Set max history entries |
$env.config.completions.external.enable = true | Enable external completions |
$env.config.cursor_shape.emacs = "line" | Set cursor shape |
$env.config.footer_mode = "25" | Show footer for large tables |
$env.config.table.mode = "rounded" | Set table border style |
| Command | Description |
|---|
$env.PATH = ($env.PATH | prepend "/usr/local/bin") | Add to PATH |
$env.PATH = ($env.PATH | append "~/.local/bin") | Append to PATH |
$env.EDITOR = "vim" | Set environment variable |
alias ll = ls -l | Create command alias |
source ~/.config/nushell/custom.nu | Source additional config |
# env.nu — environment configuration
$env.PATH = ($env.PATH | split row (char esep)
| prepend "/usr/local/bin"
| prepend ($env.HOME | path join ".cargo" "bin")
| append ($env.HOME | path join "go" "bin")
)
$env.EDITOR = "nvim"
$env.VISUAL = "nvim"
$env.PAGER = "less"
# config.nu — shell configuration
$env.config = {
show_banner: false
buffer_editor: "nvim"
table: {
mode: rounded
index_mode: auto
trim: {
methodology: wrapping
wrapping_try_keep_words: true
}
}
history: {
file_format: "sqlite"
max_size: 100_000
sync_on_enter: true
isolation: false
}
completions: {
case_sensitive: false
quick: true
partial: true
algorithm: "prefix"
external: {
enable: true
max_results: 100
}
}
}
| Command | Description |
|---|
module greet { export def hello [] { "hi" } } | Define a module inline |
use greet hello | Import command from module |
use greet * | Import all from module |
use utils.nu | Import from file module |
overlay use spam | Activate overlay |
overlay hide spam | Deactivate overlay |
overlay list | List active overlays |
# file: utils.nu
export def "str kebab" [] {
$in | str downcase | str replace -a " " "-"
}
export def "str title" [] {
$in | split row " "
| each { |w| $w | str capitalize }
| str join " "
}
# Usage:
# use utils.nu
# "Hello World" | str kebab # "hello-world"
# "hello world" | str title # "Hello World"
| Command | Description |
|---|
open data.db | Open SQLite database |
open data.db | query db "SELECT * FROM users" | Run SQL query |
open data.db | query db "SELECT * FROM users WHERE age > 30" | Filtered query |
open data.db | schema | Show database schema |
[[name age]; ["Alice" 30]] | into sqlite data.db | Create SQLite from table |
ls | into sqlite -t files data.db | Save table to SQLite |
| Command | Description |
|---|
plugin list | List installed plugins |
plugin add /path/to/plugin | Register a plugin |
plugin rm plugin_name | Remove a plugin |
plugin use plugin_name | Load a plugin |
cargo install nu_plugin_formats | Install formats plugin |
cargo install nu_plugin_query | Install query plugin |
cargo install nu_plugin_gstat | Install git status plugin |
-
Use structured data — Nushell shines when you work with tables and records rather than raw strings. Pipe commands through select, where, and sort-by instead of grep and awk.
-
Type your function parameters — Add type annotations to custom commands (name: string, count: int) to catch errors early and enable better autocomplete.
-
Prefer immutable variables — Use let by default and only use mut when you truly need mutation. This prevents accidental state changes in scripts.
-
Use SQLite history — Set $env.config.history.file_format = "sqlite" for faster searches, better corruption resistance, and richer metadata.
-
Leverage par-each for performance — When processing many items independently, par-each runs in parallel threads and can be significantly faster than each.
-
Use modules for reusable code — Organize custom commands into .nu module files and use them rather than source. Modules have proper namespacing and exports.
-
Use into for type conversions — Always use explicit type conversion (into int, into string, etc.) rather than relying on implicit coercion for reliable scripts.
-
Configure completions — Enable external completions and carapace for shell-completion support across all CLI tools.
-
Use string interpolation — Prefer $"Hello, ($name)!" over string concatenation with + for cleaner, more readable code.
-
Handle errors with try/catch — Wrap operations that might fail (file access, HTTP, parsing) in try { } catch { } blocks for robust scripts.
-
Test with describe — Use expression | describe to inspect the type of any value during development and debugging.
-
Use closures consistently — Nushell closures use { |params| body } syntax. Always include the pipe characters even for single parameters for clarity.