Dear Experts,
I have found this script on internet that can be used to execute local script remotely
#!/bin/bash
# runremote.sh
# usage: runremote.sh localscript remoteuser remotehost arg1 arg2 ...
realscript=$1
user=$2
host=$3
shift 3
# escape the arguments
declare -a args
count=0
for arg in "$@"; do
args[count]=$(printf '%q' "$arg")
count=$((count+1))
done
{
printf '%s\n' "set -- ${args[*]}"
cat "$realscript"
} | ssh $user@$host "cat | bash /dev/stdin"
Can anyone help me understand how does this below part works
{
printf '%s\n' "set -- ${args[*]}"
cat "$realscript"
} | ssh $user@$host "cat | bash /dev/stdin"
Looks extremely kludgy and pointlessly overcomplicated, I don't recommend it. This does the exact same thing without most of the nonsense and security holes.
#!/bin/sh
SCRIPT="$1"
U="$2"
H="$3"
shift 3
exec ssh "$U@$H" exec sh -s "$@" < "$SCRIPT"
One important side-effect of both methods is that the script you're running can't be interactive. It won't have keyboard access. That input channel has been used to send the script instead.
2 Likes
Because arguments are passed as strings, embedded spaces are lost normally.
The original script makes an attempt to retain arguments with embedded special characters.
The improved original script is
$ cat runremote.sh
#!/bin/bash
# runremote.sh
# usage: runremote.sh localscript remoteuser remotehost arg1 arg2 ...
realscript=$1
user=$2
host=$3
shift 3 || exit
args=$(printf "%q " "$@")
ssh "$user@$host" "bash -s $args" < "$realscript"
Demonstration example
$ cat echo.sh
for i
do
echo "$i"
done
$ /bin/bash echo.sh winter "summer time" "*"
winter
summer time
*
$ ./runremote.sh echo.sh user host winter "summer time" "*"
winter
summer time
*
3 Likes
Even when quoted via "$@" ?
Yes, with ssh the argument strings are dequoted by the local shell and then seen by the remote shell. The "$@" or a "${array[@]}" only preserves the strings for the local dequoting.
The args=$(printf "%q " "$@")
\escapes each special character, so the double dequoting works.
Other methods are args=$(printf "'%s' " "$@")
or args=$(printf "\"%s\" " "$@")
.
1 Like