1

Here are few situations I'm in. foo is the ssh server to which password less login is set up.

$ ssh foo
$ bash --login -c 'exec $0 "$@"' ls -lrt

It's working as expected.

ssh foo bash --login -c ls -lrt

This is not working as expected. Only ls is working ignoring the -lrt parameter.

And my requirement is to run the 1st example with ssh like

ssh foo bash --login -c 'exec $0 "$@"' ls -lrt

I know I've problems from the 2nd example itself. But I was just trying something to make it work and to find where the problem is. The 3rd example is not showing any error/output at all.

How do I proceed to achieve the 3rd example?

RatDon
  • 169
  • 1
  • 1
  • 6
  • Why the complication of `ssh foo bash --login -c ls -lrt` over a simpler `ssh foo 'ls -lrt'` ? – thrig Jun 02 '17 at 15:23

2 Answers2

2

You can do ssh foo bash --login -c '"exec \$0 \$@"' ls -lrt.

To find out what actually happens, strace is your friend.

ssh foo strace -vff -e execve bash --login -c 'exec $0 "$@"' ls -lrt gives me something like:

execve("/bin/bash", ["bash", "--login", "-c", "exec", "zsh", "ls", "-lrt"], [LANG=…]

My shell is zsh, which should give you a hint to what's happening here: That $0 is interpreted by the shell spawned to parse the command line sent over the SSH command. If we just escape the $0 and "$@" parts like: ssh foo strace -vff -e execve bash --login -c 'exec \$0 "\$@"' ls -lrt we get:

execve("/bin/bash", ["bash", "--login", "-c", "exec", "$0", "$@", "ls", "-lrt"], ["LANG=... As you can see here, bash is called with the arguments --login, -c, exec, $0 and so on. This doesn't get us all the way to where we want to be, since it's now effectively just calling exec by itself. To work around this, we need to quote what comes after the -c argument so it's not unpacked too early, like ssh foo strace -vff -e execve bash --login -c '"exec \$0 \$@"' ls -lrt:

execve("/bin/bash", ["bash", "--login", "-c", "exec $0 $@", "ls", "-lrt"], ["LANG=…

This is accepted by bash, since it allows you to use $@, but if you're writing proper POSIX sh, you should use "$@", in which case the right answer is ssh foo strace -vff -e execve bash --login -c '"exec \$0 \"\$@\""' ls -lrt:

execve("/bin/bash", ["bash", "--login", "-c", "exec $0 \"$@\"", "ls", "-lrt"], ["LANG=…

I assume you're using ls -lrt as a proxy for some other more complex command that actually needs bash --login and such, else just do what suggested in the first comment and use ssh foo 'ls -lrt' instead.

Tollef Fog Heen
  • 692
  • 3
  • 10
  • Thanks. You are right. That's just a proxy. The command I'm using is to use a different library and the command itself is 2-3 lines long. Thanks for the `strace` information. I was searching for something like that but couldn't word a proper search string in google. – RatDon Jun 05 '17 at 04:25
1

The ssh accepts exactly one argument as a command, therefore it should be in the quotes or apostrophes. The same applies for the bash -c argument -- it is just a single argument that is accepted. The others are passed to the bash instead of ls. The following example works just fine:

ssh foo 'bash --login -c "ls -lrt"'
Jakuje
  • 9,145
  • 2
  • 40
  • 44