Search code examples
bashsudoeofcatsu

How to `cat << 'EOF'` within `su $user <<EOF`?


##!/bin/bash
set -e
backup_dir='/home/my/backup'
user='my'

su $user <<EOFHD
cat << 'EOF' > $backup_dir/autorestartnftables.sh
#!/bin/bash
SERVICENAME="nftables"

# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi
EOF
chmod +x $backup_dir/autorestartnftables.sh
EOFHD

Above script is used to create autorestartnftables.sh,expect result as below:

#!/bin/bash
SERVICENAME="nftables"
# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi

autorestartnftables.sh after run sudo bash ./example.sh:

#!/bin/bash
SERVICENAME="nftables"
# return value is 0 if running
STATUS=0
if [[ "" -ne "0" ]]; then
        echo "Service '' is not curently running... Starting now..."
        systemctl start 
fi

Where is the problem?


Solution

  • Do not nest, nest, nest. Instead use declare -f and functions to transfer work to unrelated context.

    ##!/bin/bash
    set -e
    backup_dir='/home/my/backup'
    user='my'
    work() {
        cat << 'EOF' > $backup_dir/autorestartnftables.sh
    #!/bin/bash
    SERVICENAME="nftables"
    
    # return value is 0 if running
    STATUS=$?
    if [[ "$STATUS" -ne "0" ]]; then
            echo "Service '$SERVICENAME' is not curently running... Starting now..."
            systemctl start $SERVICENAME
    fi
    EOF
        chmod +x $backup_dir/autorestartnftables.sh
    }
    su "$user" bash -c "$(declare -p backup_dir); $(declare -f work); work"
    

    In this case, you could check if the user running your script is the user you want and then restart your script with that user:

    ##!/bin/bash
    set -e
    backup_dir='/home/my/backup'
    user='my'
    if [[ "$USER" != "$user" ]]; then
       # restart yourself as that user
       exec sudo -u "$user" "$0" "$@"
    fi
    
    cat << 'EOF' > $backup_dir/autorestartnftables.sh
    #!/bin/bash
    SERVICENAME="nftables"
    
    # return value is 0 if running
    STATUS=$?
    if [[ "$STATUS" -ne "0" ]]; then
            echo "Service '$SERVICENAME' is not curently running... Starting now..."
            systemctl start $SERVICENAME
    fi
    EOF
    chmod +x $backup_dir/autorestartnftables.sh
    

    Check your scripts with shellcheck.