macOS Terminal Commands: A Beginner's Guide

Introduction

As a Linux Systems Administrator & DevOps Engineer, I've seen firsthand how mastering terminal commands can streamline workflows and reduce manual effort. The macOS Terminal gives you direct access to powerful tools for file management, process control, text processing, and automation.

This guide is practical and task-focused. Examples target the default macOS shell (zsh on macOS 10.15 Catalina and later) and are POSIX-compatible so they will also work in bash for typical file and process operations.

What you'll learn:

  • Core file and process commands (ls, cp, mv, rm, ps, top, kill).
  • Text-processing tools and pipelines using grep, awk, sed, and find.
  • Basic shell scripting best practices (shebang, error handling, traps).
  • Security and troubleshooting tips for safe command-line use.

Work through examples on a non-production system first, and keep scripts in version control as you iterate.

About the Author

Ahmed Khalil

Ahmed Khalil is a DevOps Engineering Manager with 11 years of experience streamlining software delivery pipelines and managing infrastructure at scale. His expertise spans CI/CD automation, container orchestration, cloud infrastructure, and operating system administration. Ahmed has led teams in implementing DevOps practices that improve deployment frequency, reduce failure rates, and accelerate time-to-market for software products.

Setting Up Your Terminal: Customization and Basic Navigation

Personalizing Your macOS Terminal

Customizing Terminal improves readability and reduces fatigue. On macOS, open Terminal → Preferences to change font, color scheme, and window behavior. Modern macOS defaults to zsh as the interactive login shell (since macOS 10.15 Catalina); many scripts are POSIX-sh-compatible so they will run under bash or zsh.

Create profiles for different workflows (development, admin tasks). Use environment files to set persistent variables and aliases. For zsh, edit ~/.zshrc; for bash, edit ~/.bash_profile or ~/.bashrc. Example to set PATH and an alias:

# Open your zsh config in the default editor
nano ~/.zshrc

# Add to ~/.zshrc
export PATH="$HOME/bin:$PATH"
# On Apple Silicon Homebrew installs to /opt/homebrew/bin; Intel commonly uses /usr/local/bin
export PATH="/opt/homebrew/bin:$PATH"
alias ll='ls -la'

Save and reload with source ~/.zshrc (or open a new terminal window).

For advanced customization and a plugin/theme ecosystem, consider frameworks such as Oh My Zsh (for zsh) or Bash-it (for bash). These frameworks provide themes, common plugin sets (git, syntax highlighting, auto-suggestions), and shortcuts to enable community-driven features—install via each project's documented installer or via Homebrew where available, then enable plugins and themes in ~/.zshrc or ~/.bashrc.

Setting Description Example
Font & Size Improve readability for long sessions Use a monospaced font (e.g., Menlo), size 14–18
Color Scheme Reduce eye strain and highlight syntax Solarized Dark / High-contrast
Profiles Different presets for tasks Python Dev, Admin

Essential Commands Every Beginner Should Know

Fundamental Terminal Commands

Start with navigation and inspection commands. These are cross-shell and available on macOS out-of-the-box.

  • ls — list directory contents (use -l for details, -a for hidden files).
  • cd — change directory; cd ~ goes home, cd .. goes up one level.
  • pwd — print working directory.
  • mkdir — create a directory; mkdir -p creates parents as needed.

Quick example: move into your Projects folder and list hidden files:

cd ~/Documents/Projects
ls -la

Getting Help: man pages and --help

The built-in manual is the definitive reference for most commands. To read the manual page for a command:

man ls
# navigate with arrow keys, PageUp/PageDown
# press q to quit the man pager

Many utilities also support --help for a concise summary, e.g., grep --help. Use command -v <name> or which <name> to find the binary location.

Process Management: ps, top, kill, and monitoring

Common Commands

Process management is essential for diagnosing hung processes or high CPU usage. Use the following built-in commands first:

  • ps — list processes. Use ps aux for a detailed view of all processes.
  • top — interactive overview of CPU/memory usage; press q to exit.
  • kill <pid> — send SIGTERM (default) to a process; kill -9 <pid> sends SIGKILL (force).
  • pkill — send signals by process name (use carefully).
  • lsof — list open files, useful to find processes holding files or ports.

Examples and best practices

# Show all processes with user, pid, cpu, mem and command
ps aux | less

# Find processes consuming the most CPU
ps aux --sort=-%cpu | head -n 10

# Use top for a live view (press q to exit)
top -o cpu

# Graceful stop: try SIGTERM first
kill 12345
# If the process won't stop, escalate
kill -9 12345

# Kill processes by name (careful: this kills all matches)
pkill -f 'node server.js'

# Check which process is listening on port 8080
lsof -i :8080

Security and troubleshooting tips: always check the process owner before killing (use ps -o user,pid,cmd -p <pid>), avoid kill -9 unless necessary (it prevents cleanup), and prefer to restart services via their service manager (launchd/systemd) when available.

On macOS specifically, explore launchctl for managing launchd services. For example, launchctl list shows loaded agents and daemons; to stop a running job you can use launchctl stop <service_label>. Use these tools carefully—modifying system services may require sudo and can affect system stability.

# List loaded launchd jobs
launchctl list

# Stop a launched job by its label (replace <label> with the job name)
launchctl stop <label>

For interactive process browsing use htop (available via Homebrew: brew install htop); on Apple Silicon Homebrew paths are often /opt/homebrew/bin, while Intel machines typically use /usr/local/bin.

Terminal to launchd process flow Terminal sends commands to launchd which starts a process; monitoring tools inspect the process and signals are sent to manage it. Terminal zsh / bash submit launchd launchctl spawn Process myapp monitor top | ps | lsof | htop
Figure: Process lifecycle from Terminal → launchd → Process and monitoring tools

File Management in the Terminal: Create, Move, and Delete

Creating Files and Directories

Common commands to create files and directories:

  • touch filename — create an empty file or update timestamps.
  • mkdir foldername — create a directory; mkdir -p dir/subdir for nested creation.
  • echo 'text' > file.txt — create a file with initial content (overwrites).
touch myfile.txt
mkdir -p project/scripts
echo "#!/usr/bin/env bash" > project/scripts/run.sh
chmod u+x project/scripts/run.sh

Verify creation with ls -l.

File Operations: cp, mv, rm

Copying Files — cp

Use cp to copy files or directories. For directories use -R (recursive).

# Copy a single file
cp file.txt file.bak

# Copy a directory recursively
cp -R project project-backup

# Preserve attributes (permissions/timestamps) when copying
cp -p file.txt /path/to/backup/

Moving / Renaming — mv

mv moves or renames files and directories.

# Rename a file
mv oldname.txt newname.txt

# Move a file into a directory
mv file.txt ~/Documents/Archive/

Removing Files — rm (WITH SAFETY WARNING)

Warning: rm permanently deletes files. There is no OS-level recyclable trash when you use rm — recovery is difficult. Avoid running recursive deletes as root without verifying paths.

  • rm file.txt — remove a single file.
  • rm -r foldername — remove directory and contents (prompts may vary).
  • rm -f — force removal (suppress prompts).
  • rm -rf /path/to/dir — recursive + force: dangerous; double-check the path and never run as sudo unless absolutely necessary.

Safe practice: list files before deleting and consider moving items to a temporary folder first.

# Inspect before delete
ls -la /path/to/target

# Move to a temporary 'trash' folder in your home for safer deletion
mkdir -p ~/.local/trash
mv /path/to/target ~/.local/trash/

For repeated safe deletions consider installing a utility that integrates with the macOS Trash instead of rm, or maintain a small script that moves files to your ~/.local/trash for a grace period before permanent deletion.

File Permissions: chmod

Understanding Permissions

Unix-style permissions have three classes: owner (user), group, others. Each class can have read (r), write (w), execute (x). ls -l shows permissions in the first column (e.g., -rwxr-xr--).

Symbolic & Numeric Modes

Two common ways to use chmod:

  • Numeric (octal): chmod 755 script.sh equals rwxr-xr-x.
  • Symbolic: chmod u+x script.sh adds execute permission for the user.
# Make a script executable for the owner
chmod u+x ./deploy.sh

# Make file readable/writable by owner, readable by group and others
chmod 644 file.conf

# Common for web executables
chmod 755 /usr/local/bin/mytool

Security tip: avoid setting chmod 777 (gives write to everyone). Instead, adjust ownership with chown if needed (e.g., to assign the correct user/group). For shared directories where multiple users need to create files, consider setting the group and using the setgid bit: chgrp developers /srv/shared && chmod g+s /srv/shared. Also set a sensible umask in your shell config to avoid overly permissive defaults.

Advanced Tips and Tricks: Enhancing Your Terminal Experience

Keyboard Shortcuts & History

  • Ctrl + R — reverse-i-search command history.
  • !! — repeat last command (useful to re-run with sudo).
  • Tab — auto-complete paths and command names.
  • alias — create shortcuts (persist in ~/.zshrc or ~/.bashrc).
# Make ll persistent
echo "alias ll='ls -la'" >> ~/.zshrc
source ~/.zshrc

Troubleshooting tip: if a command returns permission denied, check file permissions with ls -l and your $PATH using echo $PATH. For missing commands, install via Homebrew (see https://brew.sh/) or check whether the binary is in /usr/local/bin (Intel) or /opt/homebrew/bin (Apple Silicon).

Use command -v <cmd> to confirm which executable will run. For Homebrew-managed tools, brew doctor helps diagnose common installation/path issues.

Shell Scripting Best Practices

When you start automating tasks, prefer small, well-tested scripts with clear error handling and logging. A few recommended practices:

  • Include a canonical shebang: #!/usr/bin/env bash or #!/usr/bin/env zsh.
  • Fail fast and handle unset variables: set -euo pipefail (works in bash; set -o pipefail in some shells).
  • Define IFS for safe splitting and use printf for logging.
  • Use trap to cleanup on errors or interrupts.
  • Lint scripts with ShellCheck (https://www.shellcheck.net/) before committing.
  • Keep scripts small, document expected inputs, and store them in Git for review and rollback.

Example: a small, robust backup script skeleton (make executable with chmod +x backup.sh):

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

trap 'echo "ERROR: script failed at line $LINENO" >&2; exit 1' ERR INT TERM

log() { printf '%s\n' "[$(date +"%Y-%m-%d %H:%M:%S")] $*"; }

main() {
  log "Starting backup"
  rsync -a --delete /path/to/src/ /path/to/dest/
  log "Backup completed"
}

main "$@"

Notes and troubleshooting:

  • macOS ships with Bash 3.2 for licensing reasons. If you need Bash 5.x features, install via Homebrew (brew install bash) and update /etc/shells if you want it as a login shell.
  • Use ShellCheck to catch unsafe subshells, quoting issues, and unhandled variables before running scripts in production.
  • Test scripts interactively and add a dry-run mode (e.g., --dry-run) for destructive operations.

AWK & sed Practical Examples

AWK — Field-based text processing

awk is great for columnar data and small aggregations. Use it inside pipelines for concise transformations.

# Print the first column of a space-separated file
awk '{print $1}' data.txt

# Use colon as delimiter (common for /etc/passwd format)
awk -F: '{print $1, $3}' /etc/passwd

# Sum numbers in the 2nd column
awk '{sum += $2} END {print sum}' metrics.txt

More advanced, real-world examples:

# Find top 5 users by accumulated %CPU from ps output
ps aux | awk 'NR>1{cpu[$1]+=$3} END{for (u in cpu) print cpu[u], u}' | sort -rn | head -n 5

# Count ERROR occurrences per logfile found by find (safe with -print0)
find /var/log -name '*.log' -print0 | xargs -0 awk '/ERROR/ {count[FILENAME]++} END {for (f in count) print count[f], f}'

# Average value in 3rd column (skip header)
awk 'NR>1 {sum += $3; n++} END {if (n) printf "%.2f\n", sum/n}' metrics.csv

sed — Stream editor for find & replace

sed performs non-interactive text transformations. On macOS prefer -E for extended regex, and use -i .bak to get a backup when editing in-place.

# Replace 'foo' with 'bar' and print to stdout
sed 's/foo/bar/g' file.txt

# Edit file in-place on macOS (create a .bak backup first)
sed -E -i .bak 's/OLD_VALUE/NEW_VALUE/g' config.ini

# Print lines 1 to 10
sed -n '1,10p' log.txt

Chained examples demonstrating broader workflows:

# Replace a config value across many files found by find (verify the list first)
find ./configs -name '*.conf' -print0 | xargs -0 sed -E -i .bak 's/(db_host=).*/\1db.example.local/'

# Extract and transform, then deduplicate results
grep -h 'ERROR' *.log | sed -E 's/.*ERROR:\s*//g' | awk '{print tolower($0)}' | sort | uniq -c | sort -rn

Security/troubleshooting: always verify outputs before using -i, keep backups or use version control, and test complex regular expressions on a small sample file.

find: Basic Usage

Common options and examples

# Find files by name (case-sensitive)
find . -type f -name '*.log'

# Find files modified in the last 7 days
find /var/log -type f -mtime -7

# Find files larger than 1 megabyte
find . -type f -size +1M

# Use -print0 with xargs -0 to safely handle filenames with spaces
find . -name '*.log' -print0 | xargs -0 grep -n 'ERROR'

# Use -exec to act on each file (dry-run: list before executing)
find . -type f -name '*.tmp' -print
# Once verified, remove:
find . -type f -name '*.tmp' -exec rm -- {} \;

Notes & best practices:

  • Always run a query that prints results first (e.g., without -exec) to verify targets.
  • Prefer -print0 + xargs -0 for safe handling of spaces and special characters in filenames.
  • On macOS the default find is the BSD variant. If you need GNU-specific options, install GNU findutils via Homebrew (which provides gfind).
  • Use -ls to get a readable listing from find during verification steps.

Security & troubleshooting:

  • Do not run destructive -exec commands as sudo until you confirm the matched set.
  • When working with system directories, ensure you understand the ownership and permissions of files you affect.
  • If a command seems slow, narrow the search path or restrict by -type, -mtime, or -size to reduce I/O.

Embrace Advanced Commands

As you grow comfortable with basics, explore combinations that automate real tasks: piping (|), redirection (>, >>), and process substitution. Commands like grep, find, awk, and sed let you search, locate, and edit content at scale.

Example to find errors across log files and show file:line matches:

find . -name '*.log' -print0 | xargs -0 grep -n 'ERROR'

When troubleshooting, combine tail -f with grep to monitor logs in real-time:

tail -f /var/log/myapp.log | grep --line-buffered 'ERROR'

Advanced tips:

  • Prefer line-buffered output (--line-buffered) for streaming pipelines that feed into grep/sed/awk.
  • For heavy text-processing workloads, consider using tools written for scale (ripgrep, jq for JSON) installed via Homebrew.
  • Document complex one-liners in a script so you can version them and test incrementally.

Conclusion: Your Next Steps in Mastering macOS Terminal

Turn knowledge into habit: replace a few GUI actions with command-line equivalents each week. Start small: create aliases, write tiny scripts (#!/usr/bin/env bash or #!/usr/bin/env zsh), and gradually add complexity. Always keep scripts under version control (Git) and document expected inputs/outputs for reliability.

Use built-in documentation with man <command> and --help. For concise examples, check tldr.sh. For Bash/Unix references, see https://www.gnu.org/. For package management on macOS, Homebrew is the common option (https://brew.sh/).

Key Takeaways

  • Master navigation and file commands first: ls, cd, cp, mv, rm.
  • Use pipelines to compose small tools: prefer | and xargs -0 for safe filenames.
  • Adopt safe scripting patterns: use shebangs, set -euo pipefail, traps, and lint with ShellCheck.
  • Test destructive commands by listing targets first and prefer moving to a local trash directory before permanent deletion.
  • Keep tools and scripts in version control and document their behavior for reproducibility.

Everyday Security Checklist

  • Inspect files before destructive commands; prefer moving to a local trash directory first.
  • Use chown and groups rather than broad permissions like 777.
  • Limit use of sudo; audit commands run with elevated privileges.
  • Keep configuration and scripts in version control; test edits before in-place replacements.

Frequently Asked Questions

What are some basic Terminal commands for beginners?
Start with pwd, cd, ls, mkdir, and touch. These let you inspect and manipulate files and directories quickly.
How can I find help for terminal commands?
Use man <command> for the manual page, or --help (e.g., grep --help). For concise, practical examples, tldr.sh provides condensed usage notes.

Published: Dec 04, 2025 | Updated: Jan 09, 2026