how can I force specific shell to be used for non-interactive command execution via ssh on remote server?

My default shell on the remote server is zsh, but I need to execute given command using /bin/sh. When I run following command, foo will be executed by zsh (as expected):

ssh -tq -l root -o LogLevel=ERROR remote-server "foo"

I have tried specifying /bin/sh -c "foo", but that only causes zsh to launch /bin/sh which then executes foo.

I need to use /bin/sh directly, not via zsh

Is there some option to ssh, or some settings either local or remote, so that I can define different shell?

Can I set different shell for all non-interactive commands (non login shell) ?

  • 2
    I don't think you can. It would allow bypassing any restrictions set by the user having a restricted shell, or /bin/false as their shell. Even the ForceCommand directive in sshd_config says "The command is invoked by using the user's login shell with the -c option." But does it matter if zsh is executed in between? It'll read zsh's startup files, instead of those of /bin/sh (if any) but there shouldn't be anything stopping you from loading those manually, or setting whatever you want from somewhere else.
    – ilkkachu
    Aug 24, 2021 at 11:40
  • Create a new user, specify /bin/sh as the login shell and use that user to perform your remote commands.
    – 111---
    Aug 24, 2021 at 12:43
  • A user should not be able to bypass its login shell in ssh, by design. If you're able to do that, it's either because you misconfigured your server or because you found a bug. @ilkkachu: zsh does not source any startup files when run non-interactively via ssh. Only bash does that.
    – user313992
    Aug 24, 2021 at 12:57
  • @ktzap, 5.1 Startup/Shutdown Files: "Commands are first read from /etc/zshenv; this cannot be overridden. [...]" -- zsh.sourceforge.io/Doc/Release/Files.html#Files In any case, I was mostly wondering why the in-between zsh could be a problem, and startup files with something really odd was the only thing I could come up with. (Which doesn't mean there couldn't be some other issue, of course.)
    – ilkkachu
    Aug 24, 2021 at 13:35
  • Depending on why you need "foo" run by sh, it may work to use emulate sh; foo as the command with zsh. That means any evaluation of foo will be sh-compatible.
    – okapi
    Aug 25, 2021 at 1:09

1 Answer 1


It's impossible to bypass the login shell, by design. You can set an SSH account whose shell is restricted (e.g. a restricted shell as in rsh/rksh/rbash/…, or a shell that only allows some specific protocol such as rssh or git-shell). The client cannot specify a different shell.

To run code in a different shell, you have to make your login shell run that shell and pass the code to the inner shell. This is no different from what you'd need to do to run interpreted code in some other language such as perl, python, etc. Take care of quoting correctly. If you don't need standard input, pass the script on standard input, so that you don't need nested quoting.

It is possible to have multiple entries in the user database for the same account. “Same account” means the same user ID. The entries must have different user names and can have different passwords, different shells, etc. See Can you give a user account multiple passwords?. Beware that this is not very robust because some programs do a lookup from the user ID (rather than from the user name in the $USER environment variable which is set to the name the user chose when logging in).

If you want zsh for interactive use but a Bourne-style shell for SSH, you can do what I do: I set my login shell to /bin/sh (or whatever it takes to have a POSIX shell), and I have (some more complicated version of) export SHELL=/bin/zsh; exec $SHELL in my .profile.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .