'How to run functions and local resources over SSH in a shell script
I have a shell script file like this:
#!/bin/bash
CONF_FILE="/tmp/settings.conf" #settings.conf contains OS_NAME="Caine Linux"
source $CONF_FILE
display_os_name() { echo "My OS is:" $OS_NAME }
#using the function locally works fine
display_os_name
#displays: My OS is: Caine Linux
#using the function on the remote host doesn't work
ssh user@host "$(declare -f); display_os_name"
#displays: My OS is:
If I remove the -f
and I use just ssh user@host "$(declare); display_os_name"
it works but displays these errors and warnings:
bash: line 10: BASHOPTS: readonly variable
bash: line 18: BASH_VERSINFO: readonly variable
bash: line 26: EUID: readonly variable
bash: line 55: PPID: readonly variable
bash: line 70: SHELLOPTS: readonly variable
bash: line 76: UID: readonly variable
If I use ssh user@host "$(declare); display_os_name >/dev/null"
to suppress the warnings only the output of the function is suppressed (My OS is: Caine Linux), not the warnings.
Is there a way to run local functions together with sourced local files on a remote SSH host?
Solution 1:[1]
An easy approach (if your local side is Linux) is to use set -a
to enable automatic export before your source
command; copy /proc/self/environ
on stdin; and parse it into a set of variables on the remote side.
Because BASHOPTS
, EUID
, etc. aren't environment variables, this avoids trying to modify them. (If you were complying with POSIX recommendations and using lowercase names for your own variables, you could even go as far as to ignore all-caps variables entirely).
set -a # enable export of all variables defined, **before** the source operation
source /tmp/settings.conf
import_env() {
while IFS= read -r -d '' item; do
printf -v "${item%%=*}" "%s" "${item#*=}" && export "$item"
done
}
cat /proc/self/environ | ssh user@host "$(declare -f); import_env; display_os_name"
Even easier is to just copy the file you want to source over the wire.
ssh user@host "$(declare -f); $(</tmp/settings.conf); display_os_name"
Solution 2:[2]
This method works using GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
#!/bin/bash
#################################################################################
source $CONF_FILE
#settings.conf contains OS_NAME="Caine Linux"
CONF_FILE="/tmp/settings.conf"
special_file='!abc123'
OS_NAME='my_server'
display_os_name()
{
echo "My OS is:" $OS_NAME
}
ssh -tt -q user@host << EOT
CONF_FILE=$CONF_FILE
special_file=$\\special_file
OS_NAME=$OS_NAME
$(typset -f display_os_name)
display_os_name
EOT
#################################################################################
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Charles Duffy |
Solution 2 |