The reason this happens is because sshd
, the server side component, invokes processes using your shell. If it's spawning an interactive shell, it spawns it as a login shell; otherwise, it uses the -c
argument to spawn a non-interactive shell to run the command you specify.
All of the operations you specified (specified commands and scp
) are non-interactive operations, so normally bash would not load .bashrc
, but bash has special-casing for when invoked by sshd
so that it invokes it anyway. If you were using zsh, then .zshenv
(which is invoked for all shells) would be loaded, but .zshrc
(which is only for interactive shells) would not be unless you were specifically loading a shell session.
In this case, if you're using bash, you're out of luck. There isn't any way to invoke an SSH command on the server side without using the shell; this is true even for scp and sftp. Most of the time, you want to use the shell because it sets up things like PATH
for various programs, and it allows for a reasonable amount of scripting of complex commands, so OpenSSH always uses it.
This also has some security benefits: if you try to log into a system account that somehow has a valid password but a shell of /usr/sbin/nologin
or /bin/false
, then you can't do anything, which is probably what the system administrator intended.
There are ways to mitigate this. Many people keep a Git repository of their dotfiles and develop them on one system, then deploy them to others. For example, I always do dotfile development on my laptop. Presumably you'd notice this problem a little sooner if any time you opened a new terminal window it immediately exited, and you might have root access to fix it yourself.
If you need to test a configuration which might lock you out, such as shell configuration or a sudoers
change, you can leave one shell (normal or root, respectively) open and then do some testing, so if you break something, you still have a way in to undo it.