10/10 --Advanced Terminal Workflows and Troubleshooting
You've learned how to navigate directories, manage files, search through content, control processes, troubleshoot networks, and write shell scripts.

Now it's time to connect all those skills.

Real terminal proficiency isn't about memorizing hundreds of commands. It's about knowing how to combine a few powerful tools to investigate problems, understand your system, and complete complex tasks efficiently.

In this final chapter of Terminal Mastery: Windows, macOS & Linux, we'll explore:

  • Advanced command-line workflows
  • Systematic troubleshooting techniques
  • Environment variables and PATH management
  • SSH and remote development
  • Logs and diagnostic information
  • Package and disk management
  • Developer workflow automation
  • Terminal productivity and customization
  • Practical troubleshooting scenarios

Let's bring everything together.

1. Think in Workflows, Not Individual Commands

A beginner often thinks:

"I need to find a file. Which command should I use?"

An experienced developer thinks:

"I need to locate the file, inspect its contents, identify the relevant information, and possibly modify it."

That's a workflow.

A workflow is a sequence of operations that solves a larger problem.

Consider this example:

You want to find every occurrence of TODO in a project, excluding dependency directories.

Linux and macOS

rg -n "TODO" . \ --glob '!node_modules/**' \ --glob '!dist/**' \ --glob '!vendor/**' 

Windows PowerShell

Get-ChildItem -Path . -Recurse -File | Where-Object { $_.FullName -notmatch '[\\/](node_modules|dist|vendor)[\\/]' } | Select-String -Pattern "TODO" 

Both commands solve the same problem, but use different approaches.

The Bash example uses ripgrep, while PowerShell combines file discovery, filtering, and text search.

The important lesson:

Don't just learn commands. Learn how to combine them.

2. Build a Systematic Troubleshooting Process

When something breaks, randomly trying commands usually wastes time.

A better approach is to investigate problems in a consistent order.

Here's a practical troubleshooting framework:

  1. Reproduce the problem.
  2. Identify the affected component.
  3. Check the relevant process or service.
  4. Inspect logs and error messages.
  5. Check configuration and environment variables.
  6. Verify filesystem permissions.
  7. Test network connectivity if necessary.
  8. Apply one change at a time.
  9. Verify that the problem is resolved.

Let's apply this process to a real development scenario.

Scenario: Your development server isn't starting

Suppose you run:

npm run dev 

But the application fails to start.

Instead of immediately reinstalling dependencies, investigate.

Step 1: Check Node.js and npm

Linux, macOS, PowerShell:

node --version npm --version 

Step 2: Check whether the expected files exist

Linux and macOS:

ls -la 

PowerShell:

Get-ChildItem -Force 

Look for:

package.json node_modules/ src/ 

Step 3: Inspect the package scripts

npm run 

This displays the available scripts defined in package.json.

Step 4: Check whether the port is already in use

Linux:

ss -ltnp 

macOS:

lsof -iTCP -sTCP:LISTEN -P -n 

Windows PowerShell:

Get-NetTCPConnection -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess 

Step 5: Identify the process

Linux and macOS:

ps aux | grep node 

PowerShell:

Get-Process node 

Step 6: Inspect the error

Don't ignore the actual error message.

It might indicate:

  • A missing dependency.
  • A syntax error.
  • An occupied port.
  • A missing environment variable.
  • An invalid configuration file.
  • A permission problem.

The goal is to identify the cause before changing the system.

3. Understand Environment Variables and PATH

Environment variables are values provided to processes by their execution environment.

They're commonly used for:

  • Configuration
  • API endpoints
  • Runtime settings
  • Credentials
  • Tool locations
  • Application modes

Display environment variables

Bash:

printenv 

PowerShell:

Get-ChildItem Env: 

Windows CMD:

set 

Read a specific variable

Bash:

echo "$HOME" echo "$PATH" 

PowerShell:

$env:USERPROFILE $env:PATH 

CMD:

echo %USERPROFILE% echo %PATH% 

Create an environment variable

Bash:

export APP_ENV="development" 

PowerShell:

$env:APP_ENV = "development" 

CMD:

set APP_ENV=development 

These examples set variables for the current shell session and its child processes.

They don't automatically create permanent system-wide settings.

What is PATH?

PATH is an environment variable containing directories where the operating system looks for executable commands.

For example, when you type:

node 

Your shell or operating system searches the relevant executable locations.

If Node.js is installed but isn't available as a command, its installation directory might be missing from PATH.

Check where an executable is located:

Linux:

command -v node 

macOS:

which node 

PowerShell:

Get-Command node 

Windows CMD:

where node 

This is one of the first things to check when a command suddenly stops working.

Inspect your PATH

Bash:

echo "$PATH" | tr ':' '\n' 

PowerShell:

$env:PATH -split ';' 

CMD:

echo %PATH% 

Be careful when modifying PATH. Accidentally replacing its existing value can make other applications unavailable from the command line.

4. SSH: Work with Remote Machines

Developers frequently work with remote servers.

For example:

  • Deploying applications.
  • Accessing Linux servers.
  • Managing cloud infrastructure.
  • Running commands on development machines.
  • Transferring files between computers.

SSH stands for Secure Shell.

It provides an encrypted connection to a remote machine.

Connect to a server

ssh username@192.168.1.100 

If the server uses a non-default SSH port:

ssh -p 7991 username@192.168.1.100 

This works from Linux, macOS, and modern Windows systems with an OpenSSH client installed.

Use an SSH key

Generate a key pair:

ssh-keygen -t ed25519 -C "developer@example.com" 

This creates a private key and a public key.

The private key must remain private.

The public key can be installed on the remote server.

On many Linux systems, you can add your public key with:

ssh-copy-id username@server-address 

If ssh-copy-id isn't available, you can install the public key manually using the server's authorized-keys mechanism.

Then connect:

ssh username@server-address 

Use SSH config

Typing a long connection command repeatedly is inconvenient.

Create or edit:

~/.ssh/config 

Add:

Host dev-server HostName 192.168.1.100 User developer Port 7991 IdentityFile ~/.ssh/id_ed25519 

Now connect using:

ssh dev-server 

This works with OpenSSH clients on Linux, macOS, and Windows.

Copy files using SCP

Upload a file:

scp app.zip username@server-address:/home/username/ 

Download a file:

scp username@server-address:/home/username/app.log . 

Copy a directory recursively:

scp -r ./project username@server-address:/home/username/ 

For more advanced synchronization, rsync is another useful tool on systems where it's available.

Example:

rsync -avz ./project/ username@server-address:/home/username/project/ 

SSH is an essential tool for developers who work with remote environments.

5. Inspect Logs Like a Professional

Logs are one of the most valuable sources of diagnostic information.

Applications, servers, and operating systems generate logs to record events.

When an application fails, logs can help explain what happened.

Read the last lines of a log

Linux and macOS:

tail -n 50 app.log 

Windows PowerShell:

Get-Content .\app.log -Tail 50 

Follow a log in real time

Linux and macOS:

tail -f app.log 

PowerShell:

Get-Content .\app.log -Wait 

This is particularly useful when testing an application while watching its output.

Search for errors

Linux and macOS:

grep -i "error" app.log 

PowerShell:

Select-String -Path .\app.log -Pattern "error" 

Combine filtering and following

You can filter a live log stream:

tail -f app.log | grep -i "error" 

Now you'll see matching error lines as they appear.

Inspect system logs on Linux

Many Linux distributions use systemd and its journal.

View recent system logs:

journalctl -n 100 

Follow logs in real time:

journalctl -f 

Inspect a specific service:

journalctl -u nginx 

View logs from the current boot:

journalctl -b 

Not every Linux distribution uses systemd, so these commands may not be available everywhere.

Inspect Windows event logs

PowerShell provides access to Windows event logs:

Get-WinEvent -LogName System -MaxEvents 20 

For application events:

Get-WinEvent -LogName Application -MaxEvents 20 

You can filter by level:

Get-WinEvent -FilterHashtable @{ LogName = "System" Level = 2 } -MaxEvents 20 

Event level 2 represents an error.

Knowing where to look is often half the troubleshooting process.

6. Disk Space and Storage Diagnostics

A full disk can cause unexpected problems:

  • Applications fail to write files.
  • Package installations stop.
  • Databases become unavailable.
  • Docker containers fail.
  • Build processes crash.

Check available disk space

Linux:

df -h 

macOS:

df -h 

PowerShell:

Get-PSDrive -PSProvider FileSystem 

Windows CMD:

wmic logicaldisk get DeviceID,Size,FreeSpace 

Note: WMIC is deprecated and may not be installed on newer Windows versions. PowerShell is generally preferable.

Find large directories

Linux:

du -sh * 

macOS:

du -sh * 

PowerShell:

Get-ChildItem -Directory | ForEach-Object { $size = ( Get-ChildItem $_.FullName -File -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum ).Sum [PSCustomObject]@{ Directory = $_.Name SizeMB = [math]::Round($size / 1MB, 2) } } | Sort-Object SizeMB -Descending 

The PowerShell example recursively measures files and can take time on large directories. It may also omit inaccessible files.

Find large files

Linux:

find . -type f -size +100M 

macOS:

find . -type f -size +100M 

PowerShell:

Get-ChildItem -File -Recurse | Where-Object { $_.Length -gt 100MB } | Select-Object FullName, Length 

Check Docker disk usage

If you're a developer using Docker, inspect its storage usage:

docker system df 

You can inspect containers and images:

docker ps -a docker images 

Don't blindly run cleanup commands such as:

docker system prune -a 

They can remove unused images, containers, networks, and build cache. Understand what will be removed before confirming a cleanup operation.

7. Package Managers: Keep Your Tools Updated

Package managers make it easier to install, update, and remove software.

Different operating systems commonly use different package managers.

Platform Package manager Example
Windows Winget winget install Git.Git
macOS Homebrew brew install git
Ubuntu/Debian APT sudo apt install git
Fedora DNF sudo dnf install git
Arch Linux Pacman sudo pacman -S git

Update package information and software

Ubuntu/Debian:

sudo apt update sudo apt upgrade 

Fedora:

sudo dnf upgrade 

macOS:

brew update brew upgrade 

Windows:

winget upgrade --all 

Package managers are not interchangeable.

Always check the package manager available on your system and review what an upgrade will change.

8. Advanced Pipelines: Connect Tools Together

One of the most powerful terminal concepts is the pipeline.

A pipeline sends the output of one command into another command.

Find the most frequently occurring values

Linux and macOS:

sort access.log | uniq -c | sort -nr | head -10 

This example:

  1. Sorts the lines.
  2. Counts repeated lines.
  3. Sorts the counts numerically in descending order.
  4. Displays the first ten results.

It is a simple way to discover repeated log entries.

Find large files and sort them

Linux and macOS:

find . -type f -printf '%s %p\n' | sort -nr | head -10 

This particular find format is supported by GNU find, not the default BSD find on macOS.

A more portable macOS alternative is:

find . -type f -exec du -h {} + | sort -hr | head -10 

The output and sorting behavior can vary slightly across platforms.

PowerShell pipeline example

PowerShell pipelines pass objects rather than just plain text.

Find the ten largest files:

Get-ChildItem -File -Recurse | Sort-Object Length -Descending | Select-Object -First 10 FullName, Length 

This is a major PowerShell advantage.

Instead of parsing formatted text, you can directly work with object properties such as:

  • Name
  • FullName
  • Length
  • LastWriteTime
  • Extension

Understanding the difference between text pipelines and object pipelines helps you write much more reliable scripts.

9. Manage Background Tasks and Long-Running Commands

Not every command finishes immediately.

Build processes, downloads, database operations, and development servers may run for a long time.

Bash: run a process in the background

npm run dev & 

The & starts the command in the background.

See background jobs:

jobs 

Bring a job to the foreground:

fg 

You can also run a process with nohup:

nohup npm run dev > app.log 2>&1 & 

This allows the process to continue after the terminal session ends in common shell environments.

However, it is not a full service manager. For production services, use an appropriate process manager or operating-system service mechanism.

PowerShell: Start-Process

Start-Process -FilePath "node" -ArgumentList "server.js" 

Start a process and redirect its output:

Start-Process ` -FilePath "node" ` -ArgumentList "server.js" ` -RedirectStandardOutput "output.log" ` -RedirectStandardError "error.log" 

Inspect running processes

Bash:

ps aux 

PowerShell:

Get-Process 

Stop a process

Bash:

kill 1234 

PowerShell:

Stop-Process -Id 1234 

Always verify the process ID before stopping a process, especially on shared or production systems.

10. Terminal Productivity: Work Faster Without Memorizing Everything

A professional terminal workflow is not just about powerful commands.

It's also about reducing friction.

1. Use command history

Bash:

history 

Search interactively in many Bash configurations:

Ctrl + R 

PowerShell:

Get-History 

You can also use Ctrl + R in common PSReadLine configurations to search history.

2. Use aliases

Bash:

alias ll='ls -lah' alias gs='git status' 

PowerShell:

Set-Alias ll Get-ChildItem 

For a more customized PowerShell alias, define a function:

function gs { git status } 

Aliases are useful for frequently repeated commands, but don't overuse them.

A script should remain understandable to someone who doesn't know your personal aliases.

3. Use tab completion

Instead of typing an entire directory name, start typing and press:

Tab 

Most modern shells support some form of completion.

It can help complete:

  • File names
  • Directory paths
  • Commands
  • Parameters
  • Git branches, with suitable configuration

4. Use terminal multiplexers

On Linux and macOS, tools such as tmux allow you to manage multiple terminal sessions in one window.

Start a session:

tmux 

Detach from a session:

Ctrl + B, then D 

List sessions:

tmux ls 

Reattach:

tmux attach 

This is especially useful when working with remote servers over SSH.

5. Customize your shell

Popular options include:

  • Zsh with Oh My Zsh
  • Starship prompt
  • PowerShell profiles
  • PSReadLine
  • Fish shell

A good terminal setup can provide:

  • Git branch information
  • Command execution duration
  • Current directory
  • Tool versions
  • Useful completions
  • Syntax highlighting

Keep customization practical. A beautiful prompt is nice, but a fast and understandable workflow is more important.

11. Practical Troubleshooting Scenarios

Let's test everything with some realistic problems.

Scenario A: Port Already in Use

You start a development server and receive:

Error: listen EADDRINUSE: address already in use 

This means another process is already listening on the requested port.

Find the process.

Linux:

sudo ss -ltnp | grep ':3000' 

macOS:

lsof -i :3000 

Windows PowerShell:

Get-NetTCPConnection -LocalPort 3000 -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess 

Find the process name in PowerShell:

Get-Process -Id 1234 

If it's safe to stop:

Stop-Process -Id 1234 

Or on Linux/macOS:

kill 1234 

Don't terminate a process until you know what it is and whether stopping it is safe.

Scenario B: Command Not Found

You run:

git 

But the shell responds:

command not found 

Possible causes:

  • Git isn't installed.
  • Git isn't in PATH.
  • The current shell hasn't loaded updated environment settings.
  • The executable has a different name.

Check:

command -v git 

PowerShell:

Get-Command git 

CMD:

where git 

If Git isn't installed, use the appropriate package manager for your platform.

Scenario C: Permission Denied

You try to execute a script:

./deploy.sh 

And receive:

Permission denied 

Check its permissions:

ls -l deploy.sh 

If it is your script and should be executable:

chmod +x deploy.sh 

Alternatively:

bash deploy.sh 

On Windows, permission problems may involve NTFS permissions, application access, or PowerShell execution policies. Diagnose the actual error rather than applying Unix permission commands to Windows.

Scenario D: DNS Resolution Failure

You try to access an API:

curl https://api.example.com 

But the hostname cannot be resolved.

Check DNS:

nslookup api.example.com 

Or:

dig api.example.com 

PowerShell:

Resolve-DnsName api.example.com 

Then check basic connectivity:

ping api.example.com 

Remember that some servers block ICMP, so a failed ping does not necessarily mean the service is unreachable.

You can also test HTTPS connectivity:

Test-NetConnection api.example.com -Port 443 

Scenario E: Application Works Locally but Not on Another Device

You start a development server:

npm run dev 

It works on your own computer but isn't accessible from another device on the same network.

Possible causes:

  • The development server listens only on localhost.
  • The firewall blocks incoming connections.
  • The devices are on different networks.
  • The server is using an unexpected port.

For Vite, you can expose the development server to the local network:

npm run dev -- --host 0.0.0.0 

Then find your local IP address.

Windows:

ipconfig 

Linux:

ip addr 

macOS:

ifconfig 

Open the application from another device using the host's LAN address and the development server's port.

Only expose development servers on networks you trust. Binding to 0.0.0.0 makes the service listen on all available network interfaces, which can expose it beyond the intended audience depending on your network and firewall configuration.

12. Create Your Personal Terminal Toolkit

At this point, you have learned many commands.

But you don't need to memorize all of them.

Instead, build a small collection of reusable scripts and notes.

A possible structure:

terminal-toolkit/ ├── bash/ │ ├── backup.sh │ ├── create-project.sh │ └── system-info.sh │ ├── powershell/ │ ├── Backup-Project.ps1 │ ├── Create-Project.ps1 │ └── Get-SystemInfo.ps1 │ ├── docs/ │ ├── networking.md │ ├── permissions.md │ └── troubleshooting.md │ └── README.md 

Keep the toolkit in a Git repository.

That gives you:

  • Version history
  • Reusable scripts
  • Documentation
  • A way to share improvements
  • A personal reference for future projects

You can gradually add scripts as you discover repetitive tasks in your daily work.

13. A Professional Terminal Checklist

Before finishing this series, check whether you can perform the following tasks.

  • [ ] Navigate between directories using absolute and relative paths.
  • [ ] Create, copy, move, rename, and delete files.
  • [ ] Search files and inspect their contents.
  • [ ] Combine commands using pipes and redirection.
  • [ ] Understand file permissions and administrative privileges.
  • [ ] Inspect and manage running processes.
  • [ ] Diagnose basic networking problems.
  • [ ] Use developer-oriented terminal tools.
  • [ ] Write Bash and PowerShell scripts.
  • [ ] Work with variables, arguments, loops, and functions.
  • [ ] Read logs and identify common errors.
  • [ ] Inspect environment variables and PATH.
  • [ ] Connect to remote machines using SSH.
  • [ ] Diagnose port conflicts and DNS failures.
  • [ ] Build reusable automation workflows.

If you can do most of these without constantly searching for examples, you're developing a strong command-line foundation.

Conclusion: The Terminal Is a Developer's Superpower

The terminal isn't an old-fashioned alternative to graphical interfaces.

It's a powerful environment for controlling your computer, automating repetitive tasks, managing remote systems, and solving problems.

Throughout this series, we've covered:

  1. Terminal fundamentals.
  2. Filesystem navigation.
  3. Searching and managing files.
  4. Pipes and command chaining.
  5. Users and permissions.
  6. Process management.
  7. Networking.
  8. Developer terminal tools.
  9. Shell scripting.
  10. Advanced workflows and troubleshooting.

The most important lesson is simple:

Don't try to memorize every command. Learn how to investigate problems, combine tools, and build workflows.

That's how you move from someone who occasionally uses the terminal to someone who can confidently work with it.

And remember: the best terminal workflow is the one that makes your work simpler, safer, and more repeatable.

Thanks for following this series!

Happy coding. 🚀

Tags: terminal productivity devtools beginners

Series: Terminal Mastery: Windows, macOS & Linux

Reading level: Intermediate