Nushell: paradigm shift in shells



This content originally appeared on DEV Community and was authored by Maksym

Introduction

Nushell (nu) is a modern shell that treats data as structured information rather than plain text. It brings spreadsheet-like data manipulation to the command line with built-in support for JSON, CSV, YAML, and other formats.

Installation

Using Package Managers

# macOS with Homebrew
brew install nushell

# Windows with Winget
winget install nushell

# Linux with Snap
snap install nushell

# Cargo (Rust package manager)
cargo install nu

From GitHub Releases

Download pre-built binaries from GitHub releases.

Basic Concepts

Structured Data Philosophy

Unlike traditional shells that work with text streams, Nushell works with structured data:

  • Everything is a table or structured data
  • Pipelines pass structured data between commands
  • Built-in understanding of common data formats

Starting Nushell

nu

Core Commands and Navigation

This would be a basic commands, that all seasond developers are know, but the way that shell treats its output would suprise most of us. I leave this commands for the newcomers, who want to learn and to master basic commands.

File System Navigation

# List directory contents (structured output)
ls

# Change directory
cd /path/to/directory

# Present working directory
pwd

# Go back to previous directory
cd -

# Go to home directory
cd ~

File Operations

# Create files
touch file.txt
"Hello World" | save hello.txt

# Copy files
cp source.txt destination.txt

# Move/rename files
mv oldname.txt newname.txt

# Remove files
rm file.txt

# Create directories
mkdir new-folder

# Remove directories
rmdir empty-folder
rm -rf folder-with-contents

Working with Structured Data

Viewing Data

# View file contents
open data.json
open data.csv
open data.yaml

# View with pagination
open large-file.txt | less

# Get file info
ls | get name size modified

Data Manipulation Commands

select – Choose specific columns

ls | select name size
ps | select name pid cpu

where – Filter rows

ls | where size > 1mb
ps | where cpu > 50
ls | where name =~ "\.txt$"  # regex match

sort-by – Sort data

ls | sort-by size
ls | sort-by modified --reverse

group-by – Group data

ls | group-by type
ps | group-by user

get – Extract specific values

ls | get 0        # First row
ls | get name     # All names
ls | get name.0   # First name

length – Count items

ls | length
ps | where name =~ "python" | length

first and last – Get specific rows

ls | first 5
ps | last 3

skip and take – Pagination

ls | skip 10 | first 5  # Skip first 10, take next 5

Data Formats

JSON

# Read JSON
open data.json

# Create JSON
{name: "John", age: 30} | to json

# Pretty print JSON
open data.json | to json --indent 2

CSV

# Read CSV
open data.csv

# Create CSV
[{name: "Alice", age: 25}, {name: "Bob", age: 30}] | to csv

# Convert other formats to CSV
open data.json | to csv

YAML

# Read YAML
open config.yaml

# Create YAML
{database: {host: "localhost", port: 5432}} | to yaml

Variables and Configuration

Variables

# Set variables
let name = "John"
let numbers = [1, 2, 3, 4, 5]
let config = {host: "localhost", port: 8080}

# Use variables
echo $name
echo $numbers
echo $config.host

Environment Variables

# View environment
env

# Set environment variable
$env.MY_VAR = "value"

# Use environment variable
echo $env.HOME
echo $env.PATH

Configuration

# View current config
config

# Edit config file
config nu

# Set config values
config set table.mode rounded

Advanced Features

Custom Commands

# Define a custom command
def greet [name: string] {
    $"Hello, ($name)!"
}

# Use the command
greet "World"

# Command with flags
def search [pattern: string, --case-sensitive] {
    if $case_sensitive {
        ls | where name =~ $pattern
    } else {
        ls | where name =~ $"(?i)($pattern)"
    }
}

Aliases

# Create aliases
alias ll = ls -la
alias gs = git status
alias la = ls -a

# View aliases
alias

Loops and Conditionals

# For loop
for file in (ls | get name) {
    echo $"Processing ($file)"
}

# Each (functional approach)
ls | each { |row| echo $"File: ($row.name)" }

# Conditional
if (ls | length) > 10 {
    echo "Many files"
} else {
    echo "Few files"
}

Error Handling

# Try-catch equivalent
try {
    open nonexistent.txt
} catch {
    echo "File not found"
}

# Default values
open config.json | get database.port? | default 3000

Working with External Commands

Running External Commands

# Run external commands
^ls -la
^git status
^python script.py

# Capture output as structured data
^ps aux | from ssv  # Space-separated values

Parsing External Command Output

# Parse various formats
^kubectl get pods -o json | from json
^docker ps --format json | lines | each { from json }

Useful Patterns and Examples

Log Analysis

# Parse log files
open server.log 
| lines 
| parse "{timestamp} {level} {message}"
| where level == "ERROR"
| group-by level
| length

System Monitoring

# Monitor processes
ps | where cpu > 80 | sort-by cpu --reverse

# Check disk usage
ls | where type == dir | insert size_mb { |row| du $row.name | get physical | math sum | $in / 1mb }

Data Processing

# CSV data analysis
open sales.csv
| group-by region
| each { |group| 
    {
        region: $group.0.region,
        total_sales: ($group | get sales | math sum),
        avg_sales: ($group | get sales | math avg)
    }
}

Git Integration

# Git status in structured format
def git-status [] {
    ^git status --porcelain | lines | parse "{status} {file}"
}

# Branch information
def git-branches [] {
    ^git branch -v | lines | parse --regex "(?<current>[\*\s])\s+(?<name>\S+)\s+(?<hash>\S+)\s+(?<message>.*)"
}

Configuration and Customization

Startup Configuration

Create ~/.config/nushell/config.nu:

# Custom prompt
$env.PROMPT_COMMAND = { 
    let path = ($env.PWD | str replace $env.HOME "~")
    $"(ansi green)($path)(ansi reset) > "
}

# Custom aliases
alias ll = ls -la
alias grep = rg

Custom Completions

# Add to config.nu
def "nu-complete git-branches" [] {
    ^git branch | lines | each { |line| $line | str trim | str replace "* " "" }
}

extern "git checkout" [
    branch?: string@"nu-complete git-branches"
]

Performance Tips

  1. Use structured commands instead of external parsing when possible
   # Good
   ls | where size > 1mb

   # Less efficient
   ^ls -la | from ssv | where size > 1mb
  1. Pipeline efficiently
   # Filter early in pipeline
   ls | where type == file | where size > 1mb | sort-by size
  1. Use built-in commands for data formats
   # Built-in JSON parsing is faster
   open data.json | get users.0.name

Debugging and Help

Getting Help

# General help
help

# Command help
help ls
help where
help config

# List all commands
scope commands

Debugging

# Debug mode
$env.RUST_LOG = "debug"

# Verbose output
ls --help

# Check command type
which ls

Migration from Traditional Shells

Common Bash → Nu Patterns

# Bash: grep pattern file.txt
# Nu:
open file.txt | lines | where $it =~ "pattern"

# Bash: find . -name "*.txt" | wc -l
# Nu:
ls **/*.txt | length

# Bash: ps aux | grep python
# Nu:
ps | where name =~ "python"

# Bash: cat file.json | jq '.users[0].name'
# Nu:
open file.json | get users.0.name

Conclusion

Nushell represents a paradigm shift in shell design, treating data as first-class citizens. Its structured approach makes data manipulation more intuitive and powerful than traditional text-based shells. Start with basic commands and gradually incorporate more advanced features as you become comfortable with the structured data philosophy.

And as always dont hesitate to leave your thoughts and criticize this article. Cheers!


This content originally appeared on DEV Community and was authored by Maksym