Linux watch Command Deep Dive: From Real-time Monitoring to Change Detection#

Time: 2026-05-11 16:57

Ever found yourself repeatedly running the same command—checking GPU usage, monitoring log file sizes, or waiting for a process to appear? Many developers manually execute commands over and over, unaware that Linux has a built-in gem: the watch command.

Core Principles of watch#

At its core, watch is simple: loop execution + full-screen display. But the implementation details are worth exploring.

Under the Hood#

// Simplified watch implementation
int main(int argc, char **argv) {
    while (1) {
        clear_screen();          // Clear terminal
        print_header();          // Show header bar
        system(argv[1]);         // Execute command
        sleep(interval);         // Wait interval
        if (exit_on_change) break; // Exit on change
    }
}

The actual watch uses execvp() (not system()), leverages ncurses for terminal control, and handles signals precisely.

Key Parameters Explained#

-n Interval Control

Default is 2 seconds, but you can customize it:

# Refresh every second (high-frequency monitoring)
watch -n 1 nvidia-smi

# Health check every 10 seconds
watch -n 10 "curl -s http://localhost/health"

Minimum interval is 0.1 seconds (watch -n 0.1), but frequent command execution may impact performance.

-d Highlight Changes

This is watch’s killer feature. It compares consecutive outputs and highlights differences:

# Highlight memory changes
watch -d free -m

# Highlight GPU memory allocation
watch -d nvidia-smi

Implementation: Split output by character, compare each position. Highlighting uses ANSI escape sequences (\e[7m reverse video).

-g Exit on Change

This turns watch from a monitor into an event trigger:

# Exit when file changes (useful in scripts)
watch -g "ls -l output.txt"
echo "File has changed!"

# Wait for process to appear
watch -g "pgrep -f 'python train.py'"
echo "Training process started"

Logic: Store current output in buffer, compare with previous, exit if different.

Real-World Scenarios#

Scenario 1: GPU Training Monitoring#

# Monitor GPU usage and memory
watch -n 1 -d nvidia-smi

Output highlights memory changes and utilization fluctuations—perfect for deep learning training monitoring.

Scenario 2: Port Tracking#

# Monitor TCP port changes
watch -n 1 -d "ss -tlnp | grep 8080"

When a service starts, port status becomes visible, and -d highlights this change.

Scenario 3: File Transfer Progress#

# Monitor large file copy progress
watch -d "ls -lh backup.tar.gz"

File size changes are highlighted in real-time—much more intuitive than repeatedly running ls.

Scenario 4: Automation Script Trigger#

#!/bin/bash
# Wait for log file to be created
watch -g "ls /var/log/app.log 2>/dev/null"

# File appeared, proceed with next steps
echo "Log file created, starting processing..."
tail -f /var/log/app.log

Performance Considerations & Pitfalls#

The Pipe Trap#

# Wrong: pipe needs quotes
watch ps aux | grep nginx  # Only monitors ps aux

# Correct: entire command needs quotes
watch "ps aux | grep nginx"

Reason: watch accepts only one command argument; pipes are split during shell parsing.

High-Frequency Monitoring Impact#

# Execute 10 times per second (excessive)
watch -n 0.1 "find / -name '*.log'"

Frequent execution of complex commands consumes significant CPU and I/O. Recommendations:

  • Simple commands (like free): 1-second refresh
  • Complex commands (like find): at least 5-second interval
  • Network requests: 10+ seconds

ANSI Color Handling#

# Default: doesn't parse color codes
watch "ls --color=auto"  # Shows garbled color codes

# Use -c to interpret colors
watch -c "ls --color=auto"  # Colors display correctly

Web Implementation: Browser-based watch#

Core approach for implementing watch in the browser:

// Browser-based watch implementation
async function watchCommand(command: string, interval: number, onHighlight: (diff: string[]) => void) {
  let lastOutput = '';

  while (true) {
    const output = await executeCommand(command);
    const diff = highlightDiff(lastOutput, output);
    onHighlight(diff);
    lastOutput = output;
    await sleep(interval);
  }
}

// Highlight differences
function highlightDiff(oldText: string, newText: string): string[] {
  const oldLines = oldText.split('\n');
  const newLines = newText.split('\n');
  const result: string[] = [];

  newLines.forEach((line, i) => {
    if (oldLines[i] !== line) {
      result.push(`[Changed] ${line}`); // Highlight marker
    } else {
      result.push(line);
    }
  });

  return result;
}

Browsers can’t execute system commands directly—you’ll need WebSocket backend proxy or Web Terminal solution (xterm.js).

Command Purpose Real-time Change Detection
watch Periodic execution Yes Supported(-d)
top/htop Process monitoring Yes Auto-refresh
tail -f Log tracking Yes No
tmux Terminal multiplexer - Manual switch

The watch command is small but mighty. Its design philosophy is worth emulating: periodic execution + change detection + full-screen display—three elements that combine to create a powerful real-time monitoring tool. Next time you need to repeatedly run a command, ask yourself: can watch automate this?