Running local script remotely with arguments

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