Shell Basics

Many of the examples in >CLI assume you’re comfortable working in a Unix-like shell environment such as Bash, Zsh, or a compatible terminal on Linux, macOS, or Windows (via WSL or Git Bash). While this book focuses on building CLIs—not teaching shell scripting—shell features like pipes and redirection are integral to how CLIs are used in the real world.

This page serves as a quick primer for essential shell constructs that frequently appear in the book’s examples. These features are part of the shell—not the CLI programs themselves—but they enable powerful workflows when chaining and scripting CLI tools.

Use Cases & Examples

Whether you’re new to the command line or just need a quick refresher, the following examples cover the basics you’ll need to follow along confidently.

Piping Output Between Commands

Piping (|) allows you to pass the output of one command directly into another command as its input, enabling powerful one-liners and chained operations.

Bash
# List all files in the current directory and pass them to grep to find Go files
ls | grep '\.go$'

# Get a list of running processes and search for instances of 'nginx'
ps aux | grep nginx

# Count the number of lines in a file that contain the word 'error'
cat /var/log/syslog | grep error | wc -l

Redirecting Output to a File

Redirection (> and >>) sends the output of a command to a file instead of the terminal, with > overwriting and >> appending. Here are a couple of overwriting examples.

Bash
# Save the list of files in the current directory to a file (overwrites if the file exists)
ls > filelist.txt


# Capture only error messages from a command and save them to a file
ls nonexistentfile 2> errors.txt

Appending Output to a File

Use >> to add command output to the end of an existing file without overwriting its contents—perfect for logs or accumulating data.

Bash
# Append disk usage stats to a log file for tracking over time
du -sh >> disk_usage.log

# Append a successful deployment message to a deployment log
echo "Deployed at $(date)" >> deploy.log

# Append the list of running processes to a file for later review
ps aux >> process_snapshot.txt

Redirecting Input from a File

Use < to feed the contents of a file as input to a command, instead of typing interactively or relying on standard input streams.

Bash
# Use a file containing SQL commands as input to the MySQL CLI
mysql -u root -p < schema.sql

# Provide a list of usernames as input to a script
./create-users.sh < usernames.txt

# Run a Python script and provide input from a data file
python3 process.py < input_data.json

Combining Redirection and Pipes

You can mix redirection (>, >>, <) with pipes (|) to build powerful, flexible command sequences that both process and store data.

Bash
# List all files, filter for .log entries, and save the results to a file
ls -l | grep ".log" > logs.txt

# Read data from a file, sort it, and append the sorted output to another file
cat unsorted.txt | sort >> sorted-results.txt

# Use grep to search for a pattern in a file and count matching lines
# Output the count to both the terminal and a file using tee
grep "ERROR" app.log | wc -l | tee error-count.txt

Discarding Output

Sometimes you want to run a command but ignore its output entirely—either to suppress noise or speed up execution. You can do this by redirecting the output to /dev/null, a special file that discards everything written to it.

Bash
# Run a command and discard its standard output
ls -l > /dev/null

# Run a command and discard its error output
ls nonexistentfile 2> /dev/null

# Run a command and discard both standard and error output
ls nonexistentfile > /dev/null 2>&1