2

I have run into a strange issue that Computer A can see Computer B, Computer B can see Computer C, but Computer A can not see Computer C.

I would like to make a bash script that can be run on A that will call arbitrary commands on C, but I can't seem to get the double quotes working properly. The idea being:

AMB_CMD='source eniron.dat; cd path/to/code/; make clean all'
ssh -t username@ComputerB "ssh -t username@ComputerC "$AMB_CMD""

I thought resolving what is to be running on B would fix it, like this:

AMB_CMD='source eniron.dat; cd path/to/code/; make clean all'
B_CMD=ssh -t username@ComputerC "$AMB_CMD"
ssh -t username@ComputerB "$B_CMD"

But I am still having issues.

hehe3301
  • 145
  • 5
  • Exactly what issues are you having? – glenn jackman Sep 17 '18 at 14:20
  • I don't think your problem is with quoting, but with the fact that the directory you're logging in in computerC is not the one where you want to run 'make clean all'. Or is it? Are you running 'make' inside $HOME? –  Sep 17 '18 at 14:21
  • @mosvy the `make clean all` is just something I put there to have something there. In my actual script I cd to the location, source and environ file, then run the make" – hehe3301 Sep 17 '18 at 14:36
  • @hehe3301 then please update your question with the exact command you're running -- notice that if that's some kind of interactive command, you also need the `-t` option to `ssh` to force it to allocate a pseudo terminal. –  Sep 17 '18 at 14:48
  • @mosvy I expanded what I need to run, I have the `-t` in my script I accidentally omitted it when posting. – hehe3301 Sep 17 '18 at 14:55
  • 1
    @hehe3301 In that case, you do have a problem with your quoting, because only `source eniron.dat` (sic) will be run on ComputerC, `cd path/to/code/; make clean all` will be run on ComputerB. Try this instead: `AMB_CMD='...'; ssh u@B ssh u@C "'$AMB_CMD'"` –  Sep 17 '18 at 15:10
  • Related: [How to execute an arbitrary simple command over ssh without knowing the login shell of the remote user?](//unix.stackexchange.com/q/205567) – Stéphane Chazelas Sep 17 '18 at 15:48
  • @mosvy the combination of `"` and `'` seems to have fixed it, if you want to type it up as an answer I'll accept it. – hehe3301 Sep 17 '18 at 16:16
  • @hehe3301 that's not possible, unfortunately. happy that I could help, anyways. –  Sep 17 '18 at 16:52

2 Answers2

3

As far as I know, no quoting of the actual command is needed.

ssh username@ComputerB ssh username@ComputerC make clean all

Or,

ssh -J username@ComputerB username@ComputerC make clean all

This would use ComputerB as a jump-host for connecting to ComputerC.

With OpenSSH 7.3+, the configuration option ProxyJump allows you to configure a jump-host in ~/.ssh/config:

Host ComputerC
    User username
    ProxyJump username@ComputerB

... so the command would be reduced to

ssh ComputerC make clean all

Depending on what your issues actually consists of (no error messages were mentioned in the question), it may have something to do with running make in the wrong directory. To cd into the correct directory before running make use the utility's -C option:

ssh username@ComputerC make -C path/to/build/dir clean all

Also, if you want to store the actual command in a variable, then don't use a single string in bash but an array:

cmd=( make -C "path/to/build/dir" clean all )

ssh ... "${cmd[@]}"
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • Unfortunately I am using a version of ssh that does not support `-J`, using your variable method I would do something like `cmd=(source eniron.dat; cd path/to/code/; make clean all)` then `ssh un@B un@C ${cmd[@]} ` – hehe3301 Sep 17 '18 at 14:59
  • Instead of `Proxyjump username@ComputerB` you can use `ProxyCommand ssh -q -W ComputerC username@ComputerB` – pLumo Sep 17 '18 at 15:55
  • That's not how `ssh` works. It only works here because none of those arguments contain special characters in any shell. See [How to execute an arbitrary simple command over ssh without knowing the login shell of the remote user?](//unix.stackexchange.com/q/205567) – Stéphane Chazelas Sep 17 '18 at 15:59
1

It's important to realise that the arguments passed to ssh are concatenated to make up a shell command line interpreted by the login shell of the remote user.

So to be able to run some-shell-code on C through a ssh connection to B, you need to build a command line for B so that the login shell of B's user interprets it to correctly to pass that some-shell-code as is to ssh.

If the current shell on A, the login shell of the user on B and the login shell of the user on C are all bash, same version (and using the same locale if some of that code contains non-ASCII characters), and $CODE contains the bash code to execute on C, you can do:

printf -v quoted_CODE %q "$CODE"
ssh B "ssh C $quoted_CODE"

If you can't be sure the login shell of the user on B or C is bash, and you don't need to pass any information over stdin, you can simply do:

ssh B ssh C bash <<< "$CODE"

Or if you know that sshd on A and B allow incoming LC_* variables (AcceptEnv LC_* common in sshd_config):

LC_CODE=$CODE ssh -o SendEnv=LC_CODE B '
  ssh -o SendEnv=LC_CODE C bash -c '\'' eval "$LC_CODE"'\'
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501