Note: This has been solved. Please see the answer here.
Wrapping ssh inside a script and passing it arbitrary commands is hard. What I am trying to do here is to come up with a generic way to invoke an ssh-wrapper, have it record the $(pwd), perform an ssh to a remote host, and at the remote host, reposition inside $(pwd), and run an arbitrary, possibly interactive, program.
Let’s first start with an ssh-wrapper
$ cat ssh-wrapper #!/bin/bash ssh -t localhost "$(pwd)/remote_script '$*'"
Then we define the remote-script
$ cat remote-script #!/bin/bash eval $*
Now let’s try some commands, and compare with what bash -c does:
$ ssh-wrapper "echo ' hi'" hi $ bash -c "echo ' hi'" hi
Notice that bash -c correctly renders the space preceding hi, but ssh-wrapper does not. This indicates potential future problems. Let’s try another case:
$ ssh-wrapper "echo hi && echo hello" hi hello $ bash -c "echo hi && echo hello" hi hello
Nothing here. Let’s try another one:
$ bash -c "FOO='a b' && echo ' hi' && echo $FOO" hi $ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO" remote_script: line 4: b: command not found
It starts to hurt here. The bash -c does the correct thing ($FOO is expanded before the value is set, which is correct), but in the ssh-wrapper, things go wrong. However, a different quoting produces a better outcome:
$ ssh-wrapper 'FOO="a b" && echo " hi" && echo $FOO' hi a b $ bash -c 'FOO="a b" && echo " hi" && echo $FOO' hi a b
This works better, and even the space preceding “hi” is present. However, we can see that ssh-wrapper is not very end user proof. And end users are non-linear: give them that script, and they will break it right away.
Let’s modify the original scripts to position the remote execution in the correct path and add a potentially interactive program:
$ cat ssh-wrapper
#!/bin/bash
ssh -t localhost "$(pwd)/remote_script $(pwd) ./prog '$*'"
$ cat remote-script
#!/bin/bash
cd $1 && $2 $3
$ cat prog
#!/bin/bash
eval "$@"
# This program traps INT and queries the user for input
function process_int {
echo -n "INT> "
read LINE
echo $LINE
exit 2
}
trap process_int SIGINT
sleep 30
The difference here is that the remote-script will place us in the path where the ssh-wrapper was originally called before calling ./prog. Now we try our command again:
$ ssh-wrapper 'FOO="a b" && echo " hi" && echo $FOO' hi a b ^CINT> it works! it works! $
You need to hit ctrl-c to get out here, then type some arbitrary string. It works, but is far from being robust: the way to make it fail is by changing the quoting:
$ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO" Executing FOO=a ^CINT> ^CConnection to localhost closed. $
We are not better off. The prog did not interpreted the whole command, only FOO=a!
This is annoying, because I may want to allow variables to be expanded on the original command line, and hence it would be very nice to allow users to use double-quotes in their argument to ssh-wrapper. In fact, it is necessary to allow either type of quoting to work, bash -c works with both, so should ssh-wrapper.
Let’s change remote-script to pass all arguments after $2:
$ cat remote-script
#!/bin/bash
cd $1 && $2 ${@:3}
And we try again:
$ ssh-wrapper "FOO='a b' && echo ' hi' && echo $FOO" ./prog: line 6: b: command not found ^CINT> ^CConnection to localhost closed.
This time, the quoting around the variable assignment is gone, so b is interpreted as a command! At this point I have run out of ideas on how to make this work.
This has been solved. Please see the answer here.
0 responses so far ↓
There are no comments yet...Kick things off by filling out the form below.