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.