Pass commands as input to another command (su, ssh, sh, etc)

Adding to tripleee‘s answer:

It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).

If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.

1. All expansions must be performed within the scope of the parent shell.

Then the delimiter of the here document must be unquoted.

command <<DELIMITER
...
DELIMITER

Example:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
    a=1
    mylogin=$(whoami)
    echo a=$a
    echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin

Output:

a=0
mylogin=leon
a=0
mylogin=leon

2. All expansions must be performed within the scope of the child shell.

Then the delimiter of the here document must be quoted.

command <<'DELIMITER'
...
DELIMITER

Example:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<'END'
    a=1
    mylogin=$(whoami)
    echo a=$a
    echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin

Output:

a=1
mylogin=root
a=0
mylogin=leon

3. Some expansions must be performed in the child shell, some – in the parent.

Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.

Example:

#!/bin/bash

a=0
mylogin=$(whoami)
sudo sh <<END
    a=1
    mylogin=\$(whoami)
    echo a=$a
    echo mylogin=\$mylogin
END
echo a=$a
echo mylogin=$mylogin

Output:

a=0
mylogin=root
a=0
mylogin=leon

Leave a Comment