How to Programmatically Send STDIN Commands to a Process Running in Screen Session


2 views

When dealing with long-running processes in Linux screen sessions, we often need to send control commands programmatically. The specific use case involves sending a "stop" command to a server process running in a screen session for scheduled maintenance.

GNU Screen creates pseudo-terminals (pty) for each window. To send commands, we need to:

  1. Identify the correct screen session
  2. Locate the specific window
  3. Inject commands into its STDIN stream

The most reliable method is using screen's built-in stuff command:

screen -S sessionname -p windowname -X stuff "stop^M"

Key components:

  • -S sessionname: Targets the specific screen session
  • -p windowname: Selects the window (default is 0)
  • -X stuff: The command injection mechanism
  • ^M: Represents the Enter key (Ctrl-V then Ctrl-M in terminal)

For a nightly restart at 3 AM:

0 3 * * * /usr/bin/screen -S myserver -p 0 -X stuff "stop^M" && sleep 10 && /path/to/start_script.sh

Using /proc filesystem:

# Find the process's STDIN fd
ls -l /proc/$(pidof your_process)/fd

# Write to it directly
echo "stop" > /proc/pid/fd/0

Note: This method often fails due to terminal security restrictions.

Always verify command execution:

#!/bin/bash
if screen -S myserver -p 0 -X stuff "stop^M"; then
    logger "Successfully sent stop command"
else
    logger "Failed to send stop command"
    exit 1
fi
  • Store screen sessions with unique names
  • Use minimal privileges in cron jobs
  • Consider process supervision (systemd, upstart) as alternative

Common issues and solutions:

Issue Solution
Permission denied Run as same user as screen session
No such session Verify session name with screen -ls
Command ignored Ensure proper line endings (^M)

When managing long-running server processes in Linux screen sessions, we often need to send commands to the process's STDIN programmatically. This becomes crucial for:

  • Automated graceful shutdowns
  • Scheduled maintenance operations
  • Remote process control
  • Cron-based automation

Screen maintains a separate pseudo-terminal for each window, making direct STDIN injection non-trivial. Here's why traditional methods fail:


# These WON'T work:
echo "stop" > /proc/[pid]/fd/0
echo "stop" | screen -S mysession -X stuff

The correct approach uses screen's built-in control capabilities:


# Basic command format:
screen -S [session_name] -p [window_number] -X stuff "stop$(printf \\r)"

# Practical example for nightly restart:
screen -S game_server -p 0 -X stuff "stop$(printf \\r)"
sleep 30
screen -S game_server -p 0 -X stuff "./start_server.sh$(printf \\r)"

Here's a complete cron-ready solution:


#!/bin/bash
SESSION="my_server"
WINDOW=0
LOGFILE="/var/log/server_restart.log"

# Send stop command
screen -S $SESSION -p $WINDOW -X stuff "stop$(printf \\r)"
echo "$(date) - Sent stop command" >> $LOGFILE

# Wait for shutdown
sleep 30

# Verify process stopped
if ! pgrep -f "server_process"; then
    # Restart
    screen -S $SESSION -p $WINDOW -X stuff "./start_server.sh$(printf \\r)"
    echo "$(date) - Restarted server" >> $LOGFILE
else
    echo "$(date) - ERROR: Process still running" >> $LOGFILE
    exit 1
fi

For production environments, consider these enhancements:

  • Add PID verification with timeout loops
  • Implement proper error handling
  • Include notification mechanisms (email, Slack, etc.)
  • Add pre-stop sanity checks (active connections, etc.)

If commands aren't being received:


# 1. Verify screen session is attached (or use -d -m for detached)
screen -list

# 2. Check the correct window number
screen -S [session] -X windows

# 3. Ensure proper line endings (notice the $(printf \\r))