How to Create and Run Commands in a Detached Screen Session Without Attaching


2 views

When automating system administration tasks with GNU Screen, we often need to:

  • Create detached screen sessions
  • Execute commands within them
  • Maintain session persistence

The standard approach of using screen -d -m -S session_name works for creation, but command execution becomes tricky when we need to:

# This works only after initial attachment
screen -S my_session -X stuff "cd /path/to/scripts$(printf \\r)"
screen -S my_session -X stuff "./start_service.sh$(printf \\r)"

Here's a bulletproof method to execute commands in a freshly created screen:

# Create session with initial command
screen -dmS maintenance_session /bin/bash -c 'cd /opt/app/; ./maintenance_script.sh; exec bash'

This approach:

  • Starts bash as the shell
  • Changes directory and runs the script
  • Keeps the session alive with 'exec bash'

For scripts that might terminate but need the session to persist:

#!/bin/bash
# Create persistent wrapper
cat << 'EOF' > /tmp/screen_wrapper.sh
#!/bin/bash
/path/to/actual_script.sh
# Keep shell open after completion
exec bash
EOF

chmod +x /tmp/screen_wrapper.sh
screen -dmS persistent_session /tmp/screen_wrapper.sh

For complex initialization sequences:

screen -dmS complex_init bash -c '\
  cd /var/log/app/; \
  ./rotate_logs.sh; \
  ./start_service.sh --debug; \
  exec bash'

Add robust checking to your automation:

if ! screen -list | grep -q "maintenance_session"; then
  screen -dmS maintenance_session bash -c '\
    trap "echo Cleaning up..." EXIT; \
    ./critical_process.sh; \
    exec bash'
  sleep 1 # Allow time for initialization
  screen -S maintenance_session -X logfile /var/log/screen_${timestamp}.log
  screen -S maintenance_session -X log
fi

Here's a complete automation script example:

#!/bin/bash
SESSION="auto_maintenance"
LOG_DIR="/var/log/screen_logs"
mkdir -p "$LOG_DIR"

# Kill existing session if needed
screen -XS "$SESSION" quit

# Create new session with persistence
screen -dmS "$SESSION" bash -c '\
  cd /opt/automation/; \
  source ./env_setup.sh; \
  while true; do \
    ./main_loop.sh; \
    sleep 60; \
  done; \
  exec bash'

# Verify creation
if screen -list | grep -q "$SESSION"; then
  # Configure logging
  timestamp=$(date +%Y%m%d_%H%M%S)
  screen -S "$SESSION" -X logfile "$LOG_DIR/${SESSION}_${timestamp}.log"
  screen -S "$SESSION" -X log
  
  echo "Session $SESSION created and configured"
else
  echo "Failed to create session $SESSION" >&2
  exit 1
fi

When automating server maintenance tasks, many sysadmins need to execute commands in persistent GNU Screen sessions without manual attachment. The standard approach using screen -d -m -S session_name creates the session, but subsequent command execution often fails until the session has been manually attached at least once.

Here's the most robust method I've found for creating a screen session and immediately executing commands:


# Create screen with initial command
screen -dmS maintenance_session /bin/bash -c 'cd /opt/scripts && ./monitor.sh; exec bash'

This approach:

  • Creates detached session (-dm)
  • Names the session (-S)
  • Runs commands through bash -c
  • Keeps session alive with exec bash

For complex command sequences, create a wrapper script:


#!/bin/bash
# maintenance_wrapper.sh
cd /opt/scripts
source ./config.env
./start_monitoring.sh --log-level=debug
exec bash

Then launch with:

screen -dmS monitoring_session ./maintenance_wrapper.sh

The key to keeping the session alive after command completion is the exec bash trick. This replaces the current shell with a new interactive bash instance after your commands finish.

For existing sessions where you can't modify the initial command:


screen -S existing_session -X stuff $'cd /opt/scripts\n./run.sh\n'
screen -S existing_session -X stuff $'exec bash\n'

Note the use of $'' syntax for proper newline handling.

Here's a complete automation script I use for log rotation:


#!/bin/bash
SESSION="log_rotation_$(date +%s)"

# Create and configure session
screen -dmS $SESSION /bin/bash -c '
    cd /var/log
    ./compress_old_logs.sh
    ./update_log_index.sh
    exec bash
'

# Verify creation
if screen -ls | grep -q $SESSION; then
    echo "Rotation session started successfully"
else
    echo "Failed to start rotation session" >&2
    exit 1
fi