How to Run a Shell Script as Another User in Linux (su, sudo, and runuser Examples)


3 views

When automating system administration tasks, you often need to execute scripts with different user privileges. The challenge is doing this securely and correctly while maintaining the target user's environment.

The simplest approach is using su with the -c flag to execute a single command:

su postgres -c "/path/to/backup_db.sh /tmp/test"

Key points:

  • This inherits the postgres user's environment
  • Works interactively (will prompt for password)
  • For automation, you'll need to handle authentication

For more control, sudo is often preferred:

sudo -u postgres /path/to/backup_db.sh /tmp/test

Advantages:

  • More granular control via sudoers file
  • Can be configured for passwordless execution
  • Better logging of privileged operations

For system services, runuser is often better:

runuser -u postgres -- /path/to/backup_db.sh /tmp/test

This is particularly useful in:

  • Systemd service files
  • Container environments
  • Situations where pseudo-terminal allocation isn't needed

To preserve specific environment variables when switching users:

sudo -Hu postgres env PATH=$PATH /path/to/backup_db.sh /tmp/test

For fully automated execution:

  1. Configure passwordless sudo for specific commands
  2. Set up proper permissions on the script
  3. Consider using SSH key authentication if running remotely

Here's a complete example with error handling:

#!/bin/bash

SCRIPT="/opt/scripts/backup_db.sh"
ARGS="/tmp/backup"
LOG="/var/log/db_backup.log"

if sudo -u postgres "$SCRIPT" "$ARGS" >> "$LOG" 2>&1; then
    echo "Backup completed successfully"
    exit 0
else
    echo "Backup failed - check $LOG for details" >&2
    exit 1
fi
  • Always use absolute paths
  • Limit sudo privileges to specific commands
  • Regularly audit scripts run with elevated privileges
  • Consider using dedicated service accounts

When automating system tasks in Linux, we often need to execute scripts with different user privileges. The manual approach using su works interactively but fails in automated environments because:

  • It requires interactive password input
  • Environment variables aren't properly inherited
  • The session doesn't terminate automatically

The most robust method combines sudo with proper configuration:

sudo -u postgres /path/to/backup_db.sh /tmp/test

Key advantages:

1. Non-interactive execution
2. Preserves target user's environment
3. Clean permission handling

First, edit the sudoers file safely with visudo, then add:

# Allow script_user to run backup_db.sh as postgres
script_user ALL=(postgres) NOPASSWD: /path/to/backup_db.sh

For systems where sudo isn't available, use expect:

#!/usr/bin/expect -f
spawn su - postgres -c "/path/to/backup_db.sh /tmp/test"
expect "Password:"
send "postgres_password\r"
interact

When switching users, environment variables may behave differently. Test with:

sudo -u postgres env

To preserve specific variables:

sudo -u postgres -E /path/to/script.sh

Here's a complete backup script solution:

#!/bin/bash
# Configure in /etc/sudoers:
# backup_user ALL=(postgres) NOPASSWD: /usr/local/bin/pg_backup.sh

BACKUP_DIR=/var/backups/postgres
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

sudo -u postgres pg_dumpall | gzip > ${BACKUP_DIR}/pg_backup_${TIMESTAMP}.sql.gz
find ${BACKUP_DIR} -type f -mtime +30 -delete