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:
- Identify the correct screen session
- Locate the specific window
- 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))