Skip to content

Nushell

Modern structured-data shell that treats command output as tables and supports pipelines with typed data, filtering, and cross-platform scripting.

CommandDescription
brew install nushellInstall on macOS with Homebrew
cargo install nuInstall from crates.io
winget install nushellInstall on Windows with winget
sudo apt install nushellInstall on Debian/Ubuntu
pacman -S nushellInstall on Arch Linux
nix-env -i nushellInstall on NixOS
nuLaunch Nushell
nu --versionShow installed version
nu -c "ls"Run a single command and exit
nu script.nuExecute a Nushell script file
chsh -s /usr/bin/nuSet Nushell as default shell
CommandDescription
sysShow full system information
sys hostShow host details (name, OS, kernel)
sys memShow memory usage
sys cpuShow CPU information
sys disksShow disk usage
sys netShow network interfaces
sys tempShow temperature sensors
date nowShow current date and time
date now | format date "%Y-%m-%d"Format current date
$nu.home-pathShow home directory path
$nu.os-infoShow OS details
CommandDescription
lsList files as structured table
ls -lLong listing with details
ls -aShow hidden files
ls **/*.rsRecursive glob for Rust files
ls | where size > 1mbFilter files larger than 1MB
ls | where type == dirFilter for directories only
ls | sort-by modified -rSort by modification date (newest first)
ls | sort-by size -rSort by size descending
ls | get nameGet only file names column
CommandDescription
psList processes as table
ps | where cpu > 10Find processes using >10% CPU
ps | where name =~ "node"Find processes by name pattern
ps | sort-by mem -r | first 10Top 10 processes by memory
ps | where pid == 1234Find process by PID
CommandDescription
helpShow general help
help commandsList all available commands
help lsShow help for specific command
help operatorsList available operators
help escapesShow string escape sequences
CommandDescription
ls | select name sizeSelect specific columns
ls | reject modifiedRemove specific columns
ls | rename filename filesizeRename columns
ls | first 5Get first 5 rows
ls | last 3Get last 3 rows
ls | skip 10Skip first 10 rows
ls | lengthCount number of rows
ls | reverseReverse row order
ls | shuffleRandomize row order
ls | flattenFlatten nested tables
ls | columnsList column names
CommandDescription
ls | where size > 1mbFilter 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 -rSort descending
ls | sort-by name -iSort case-insensitive
ls | uniq-by typeRemove duplicates by column
ls | group-by typeGroup rows by column value
CommandDescription
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 | enumerateAdd index column
ls | window 3Sliding window of 3 rows
ls | zip [1 2 3]Zip with another list
ls | transposeSwap rows and columns
CommandDescription
42Integer
3.14Float
"hello"String
true / falseBoolean
nullNull value
2024-01-15Date
5sec / 3min / 2hrDuration
1kb / 5mb / 2gbFile size
0b1010Binary literal
0xffHexadecimal literal
CommandDescription
[1 2 3]List
[1 2 3] | append 4Append to list
[1 2 3] | prepend 0Prepend to list
{name: "Alice", age: 30}Record
{a: 1} | merge {b: 2}Merge records
[[name age]; ["Alice" 30] ["Bob" 25]]Table literal
0..9Range (0 to 9)
0..<9Exclusive range (0 to 8)
0..2..10Range with step (0, 2, 4, 6, 8, 10)
CommandDescription
"42" | into intString to integer
"3.14" | into floatString to float
42 | into stringNumber to string
"true" | into boolString to boolean
"2024-01-15" | into datetimeString to datetime
1024 | into filesizeNumber to filesize
5 | into duration --unit secNumber to duration
42 | into binaryNumber to binary
[1 2 3] | into recordList to record
{a: 1} | into recordConvert to record
CommandDescription
open data.jsonOpen and parse JSON file
open data.csvOpen and parse CSV file
open data.yamlOpen and parse YAML file
open data.tomlOpen and parse TOML file
open data.xmlOpen and parse XML file
open data.tsvOpen and parse TSV file
open data.sqliteOpen SQLite database
open file.txtOpen as plain text
open data.json | get usersOpen and navigate into data
CommandDescription
"hello" | save hello.txtSave string to file
ls | save files.jsonSave table as JSON
ls | save files.csvSave table as CSV
ls | save files.yamlSave table as YAML
open data.json | to csvConvert JSON to CSV
open data.csv | to jsonConvert CSV to JSON
open data.json | save data.yamlConvert between formats
open data.csv | save -f data.csvForce overwrite existing file
"line1\nline2" | save -a log.txtAppend to file
CommandDescription
open file.txt | linesSplit file into lines
open file.txt | lines | lengthCount lines in file
open file.csv | where status == "active"Filter CSV rows
open file.json | select name emailPick fields from JSON
open file.json | to yaml | save file.yamlConvert JSON to YAML
glob "**/*.md" | each { |f| open $f }Open all matching files
CommandDescription
"hello world" | str upcaseConvert to uppercase
"HELLO" | str downcaseConvert to lowercase
"hello" | str capitalizeCapitalize first letter
" hello " | str trimTrim whitespace
"hello" | str trim --char "h"Trim specific character
"hello" | str reverseReverse string
CommandDescription
"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
CommandDescription
"hello world" | split row " "Split by delimiter
"a,b,c" | split row ","Split CSV-style string
"hello" | split charsSplit into characters
["hello" "world"] | str join " "Join list into string
["a" "b" "c"] | str join ","Join with comma
"hello" | str lengthGet string length
"hello world" | str substring 0..5Extract 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'#
CommandDescription
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
CommandDescription
let x = 42Immutable variable
mut x = 0; $x = $x + 1Mutable variable
const PI = 3.14159Compile-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
CommandDescription
[1 2 3 4 5] | math sumSum of values
[1 2 3 4 5] | math avgAverage of values
[1 2 3 4 5] | math minMinimum value
[1 2 3 4 5] | math maxMaximum value
[1 2 3 4 5] | math medianMedian value
[1 2 3 4 5] | math stddevStandard deviation
[1 2 3 4 5] | math varianceVariance
[1 2 3] | math productProduct of values
10 | math absAbsolute value
10 | math sqrtSquare root
2 | math round -p 2Round to precision
10 | math log 2Logarithm base 2
CommandDescription
http get https://api.example.com/dataGET 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/1DELETE request
http get url --headers [Accept application/json]GET with custom headers
http get url | get dataGET and extract field
port 8080Check 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)"]
CommandDescription
$nu.config-pathShow config file path
$nu.env-pathShow env config file path
$nu.default-config-dirShow config directory
config nuOpen config in editor
config envOpen env config in editor
CommandDescription
$env.config.show_banner = falseDisable 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_000Set max history entries
$env.config.completions.external.enable = trueEnable 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
CommandDescription
$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 -lCreate command alias
source ~/.config/nushell/custom.nuSource 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
    }
  }
}
CommandDescription
module greet { export def hello [] { "hi" } }Define a module inline
use greet helloImport command from module
use greet *Import all from module
use utils.nuImport from file module
overlay use spamActivate overlay
overlay hide spamDeactivate overlay
overlay listList 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"
CommandDescription
open data.dbOpen 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 | schemaShow database schema
[[name age]; ["Alice" 30]] | into sqlite data.dbCreate SQLite from table
ls | into sqlite -t files data.dbSave table to SQLite
CommandDescription
plugin listList installed plugins
plugin add /path/to/pluginRegister a plugin
plugin rm plugin_nameRemove a plugin
plugin use plugin_nameLoad a plugin
cargo install nu_plugin_formatsInstall formats plugin
cargo install nu_plugin_queryInstall query plugin
cargo install nu_plugin_gstatInstall git status plugin
  1. 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.

  2. Type your function parameters — Add type annotations to custom commands (name: string, count: int) to catch errors early and enable better autocomplete.

  3. Prefer immutable variables — Use let by default and only use mut when you truly need mutation. This prevents accidental state changes in scripts.

  4. Use SQLite history — Set $env.config.history.file_format = "sqlite" for faster searches, better corruption resistance, and richer metadata.

  5. Leverage par-each for performance — When processing many items independently, par-each runs in parallel threads and can be significantly faster than each.

  6. Use modules for reusable code — Organize custom commands into .nu module files and use them rather than source. Modules have proper namespacing and exports.

  7. Use into for type conversions — Always use explicit type conversion (into int, into string, etc.) rather than relying on implicit coercion for reliable scripts.

  8. Configure completions — Enable external completions and carapace for shell-completion support across all CLI tools.

  9. Use string interpolation — Prefer $"Hello, ($name)!" over string concatenation with + for cleaner, more readable code.

  10. Handle errors with try/catch — Wrap operations that might fail (file access, HTTP, parsing) in try { } catch { } blocks for robust scripts.

  11. Test with describe — Use expression | describe to inspect the type of any value during development and debugging.

  12. Use closures consistently — Nushell closures use { |params| body } syntax. Always include the pipe characters even for single parameters for clarity.