Loading learning content...
Despite their limitations, FIFOs remain valuable in specific scenarios where their simplicity and filesystem integration provide elegant solutions. This page explores real-world use cases where named pipes excel, demonstrating patterns you can apply in your own systems.
From logging infrastructure to service control interfaces, FIFOs continue to power production systems across the Unix world.
By the end of this page, you will understand:
• Logging and monitoring pipelines using FIFOs • Service control and administration patterns • Shell scripting integration techniques • Process pool and worker patterns • Testing and development utilities
One of the most common FIFO applications is centralized logging. Multiple applications write log entries to a FIFO, while a log processor reads, filters, and routes messages.
Advantages for Logging:
1234567891011121314151617181920212223242526272829303132333435
#!/bin/bash# Centralized log collector using FIFO LOG_FIFO="/var/run/myapp/logs.fifo"LOG_DIR="/var/log/myapp" # Create FIFO if neededmkdir -p "$(dirname "$LOG_FIFO")"[ -p "$LOG_FIFO" ] || mkfifo -m 0622 "$LOG_FIFO" # Log processor: reads from FIFO, routes by severitywhile true; do # Open FIFO for reading (blocks until writer connects) while IFS= read -r line; do timestamp=$(date '+%Y-%m-%d %H:%M:%S') # Route based on severity prefix case "$line" in ERROR:*) echo "[$timestamp] $line" >> "$LOG_DIR/error.log" # Also alert on errors echo "$line" | mail -s "App Error" admin@example.com & ;; WARN:*) echo "[$timestamp] $line" >> "$LOG_DIR/warn.log" ;; *) echo "[$timestamp] $line" >> "$LOG_DIR/app.log" ;; esac done < "$LOG_FIFO" # FIFO closed (all writers gone), reopen sleep 1done12345678910111213141516171819202122232425262728293031323334353637
#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <stdarg.h>#include <time.h> #define LOG_FIFO "/var/run/myapp/logs.fifo" static int log_fd = -1; int log_init(void) { log_fd = open(LOG_FIFO, O_WRONLY | O_NONBLOCK); return log_fd >= 0 ? 0 : -1;} void log_message(const char *level, const char *fmt, ...) { if (log_fd < 0) return; char buf[1024]; int offset = snprintf(buf, sizeof(buf), "%s: ", level); va_list args; va_start(args, fmt); offset += vsnprintf(buf + offset, sizeof(buf) - offset, fmt, args); va_end(args); // Ensure newline and atomic write if (offset < sizeof(buf) - 1) buf[offset++] = ''; write(log_fd, buf, offset); // Atomic if <= PIPE_BUF} // Usage:// log_init();// log_message("INFO", "User %s logged in", username);// log_message("ERROR", "Database connection failed: %s", error);FIFOs provide simple command interfaces for daemons and services. A control FIFO allows external tools to send commands to a running service without complex protocols.
Pattern:
┌──────────────┐ control.fifo ┌─────────────┐
│ Control CLI │ ─────────────────────> │ Daemon │
└──────────────┘ └─────────────┘
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <sys/stat.h>#include <unistd.h>#include <signal.h> #define CONTROL_FIFO "/var/run/mydaemon/control.fifo" volatile sig_atomic_t running = 1;volatile sig_atomic_t reload_config = 0;volatile sig_atomic_t dump_stats = 0; void handle_command(const char *cmd) { if (strncmp(cmd, "SHUTDOWN", 8) == 0) { printf("Received SHUTDOWN command"); running = 0; } else if (strncmp(cmd, "RELOAD", 6) == 0) { printf("Received RELOAD command"); reload_config = 1; } else if (strncmp(cmd, "STATUS", 6) == 0) { printf("Received STATUS command"); dump_stats = 1; } else if (strncmp(cmd, "LOGLEVEL ", 9) == 0) { int level = atoi(cmd + 9); printf("Setting log level to %d", level); // set_log_level(level); } else { printf("Unknown command: %s", cmd); }} int main(void) { // Setup control FIFO unlink(CONTROL_FIFO); mkdir("/var/run/mydaemon", 0755); if (mkfifo(CONTROL_FIFO, 0600) < 0) { perror("mkfifo"); return 1; } printf("Daemon started, control FIFO: %s", CONTROL_FIFO); // Main loop with control FIFO monitoring while (running) { // Non-blocking open to allow periodic other work int ctrl_fd = open(CONTROL_FIFO, O_RDONLY | O_NONBLOCK); if (ctrl_fd >= 0) { // Keep reading until empty or closed char buf[256]; ssize_t n; while ((n = read(ctrl_fd, buf, sizeof(buf) - 1)) > 0) { buf[n] = '\0'; // Remove trailing newline char *nl = strchr(buf, ''); if (nl) *nl = '\0'; handle_command(buf); } close(ctrl_fd); } // Do other daemon work... if (reload_config) { printf("Reloading configuration..."); reload_config = 0; } sleep(1); } unlink(CONTROL_FIFO); printf("Daemon shutdown complete"); return 0;}12345678910111213141516171819202122
#!/bin/bash# Simple CLI to control the daemon CONTROL_FIFO="/var/run/mydaemon/control.fifo" send_command() { if [ -p "$CONTROL_FIFO" ]; then echo "$1" > "$CONTROL_FIFO" echo "Command sent: $1" else echo "Error: Daemon not running (FIFO not found)" exit 1 fi} case "$1" in stop) send_command "SHUTDOWN" ;; reload) send_command "RELOAD" ;; status) send_command "STATUS" ;; loglevel) send_command "LOGLEVEL $2" ;; *) echo "Usage: $0 {stop|reload|status|loglevel N}" ;;esacFIFOs extend shell pipelines beyond linear sequences. They enable complex data flow topologies like tees, joins, and multiplexers.
Example: Processing Output Multiple Ways
12345678910111213141516171819202122
#!/bin/bash# Process log file through multiple analysis pipelines simultaneously LOG_FILE="/var/log/access.log"FIFO1="/tmp/pipeline_errors.fifo"FIFO2="/tmp/pipeline_stats.fifo" # Create FIFOsmkfifo "$FIFO1" "$FIFO2" # Start consumers in background# Consumer 1: Count errors by typegrep "ERROR" < "$FIFO1" | sort | uniq -c > /tmp/error_counts.txt & # Consumer 2: Calculate request statisticsawk '{sum+=$NF; count++} END {print "Avg:", sum/count}' < "$FIFO2" & # Producer: tee log to both FIFOstail -f "$LOG_FILE" | tee "$FIFO1" > "$FIFO2" # Cleanuprm -f "$FIFO1" "$FIFO2"Bash's process substitution (<() and >()) uses FIFOs internally:
# These are equivalent:
diff <(sort file1) <(sort file2)
# Under the hood, bash creates:
mkfifo /dev/fd/63 /dev/fd/62
sort file1 > /dev/fd/63 &
sort file2 > /dev/fd/62 &
diff /dev/fd/63 /dev/fd/62
Process substitution is cleaner for simple cases; explicit FIFOs offer more control.
FIFOs enable communication between programs written in different languages. Since FIFOs use standard file I/O, any language can participate.
Example: Python Frontend, C Backend
123456789101112131415161718192021222324252627282930313233343536
#!/usr/bin/env python3"""Python client sending work to C backend via FIFO."""import osimport json REQUEST_FIFO = "/tmp/work_requests.fifo"RESPONSE_FIFO = f"/tmp/response_{os.getpid()}.fifo" def send_request(data): # Create response FIFO if os.path.exists(RESPONSE_FIFO): os.unlink(RESPONSE_FIFO) os.mkfifo(RESPONSE_FIFO, 0o600) try: # Send request with response FIFO path request = { "data": data, "response_fifo": RESPONSE_FIFO } with open(REQUEST_FIFO, 'w') as f: f.write(json.dumps(request) + '') # Wait for response with open(RESPONSE_FIFO, 'r') as f: response = json.loads(f.readline()) return response finally: os.unlink(RESPONSE_FIFO) # Usageresult = send_request({"numbers": [1, 2, 3, 4, 5]})print(f"Sum: {result['sum']}, Product: {result['product']}")Benefits of FIFO-Based Inter-Language IPC:
FIFOs are excellent for testing and debugging scenarios where you need to control or inspect inter-process communication.
Common Testing Patterns:
12345678910111213141516171819202122232425262728293031323334353637383940414243
#!/bin/bash# Test harness using FIFOs for controlled I/O STDIN_FIFO="/tmp/test_stdin.fifo"STDOUT_FIFO="/tmp/test_stdout.fifo" setup_test() { mkfifo "$STDIN_FIFO" "$STDOUT_FIFO"} run_program_under_test() { # Run program with controlled stdin/stdout ./my_program < "$STDIN_FIFO" > "$STDOUT_FIFO" & PROGRAM_PID=$!} send_input() { echo "$1" > "$STDIN_FIFO"} expect_output() { local expected="$1" local actual read -t 5 actual < "$STDOUT_FIFO" if [ "$actual" = "$expected" ]; then echo "PASS: Got expected output" else echo "FAIL: Expected '$expected', got '$actual'" return 1 fi} # Example testsetup_testrun_program_under_test send_input "HELLO"expect_output "WORLD" send_input "QUIT" cleanup_testFIFOs appear in several well-known production systems:
| System | FIFO Usage | Purpose |
|---|---|---|
| MySQL | mysql.sock (Unix socket, similar concept) | Client-server communication |
| Apache/Nginx | Logging to FIFOs | Real-time log processing without disk I/O |
| Systemd | sd_notify mechanism | Service readiness notification |
| GNU Screen/tmux | Control sockets/FIFOs | Session attachment and control |
| CUPS (printing) | Backend communication | Print job spooling |
Nginx can log to FIFOs for real-time processing:
access_log /var/run/nginx/access.fifo combined;
A separate process reads the FIFO to: • Stream logs to Elasticsearch • Calculate real-time metrics • Feed anomaly detection systems
This decouples Nginx from log processing overhead.
Congratulations! You've completed the Named Pipes (FIFOs) module. You now understand FIFO creation, unrelated process communication, blocking behavior, limitations, and practical use cases. FIFOs remain a powerful tool in the Unix IPC toolkit—simple, efficient, and universally available.