SSHing into system with ZSH as default shell doesn't run /etc/profile
Solution 1
ZSH just works in this way. /etc/profile
is NOT an init file for ZSH. ZSH uses /etc/zprofile
and ~/.zprofile
.
Init files for ZSH:
/etc/zshenv
~/.zshenv
- login mode:
/etc/zprofile
~/.zprofile
- interactive:
/etc/zshrc
~/.zshrc
- login mode:
/etc/zlogin
~/.zlogin
Tips:
- Default shell opened in your terminal on Linux is a non-login, interactive shell. But on macOS, it's a login shell.
References
Solution 2
sshd
runs a login shell when the client doesn't send any command to run. That's to mimic the behaviour of rsh
which was calling the rlogind
service instead of the rshd
one when not given any command to run.
To tell the shell it is to be a login shell, like rlogind
or login
or telnetd
, sshd
starts your shell with an argv[0]
that starts with a -
.
Or course, zsh
like every other shell understands it as well. If it didn't, it couldn't ever be invoked in login mode.
Here, the symptom that made you think you didn't get a login shell was because /etc/profile
was not interpreted.
/etc/profile
is the login session initialisation file for Bourne-like shells. Syntax in there is expected to be in the Bourne shell syntax (or possibly POSIX sh syntax as the Bourne shell is hardly ever used these days) and is read upon login by all the shells whose syntax is (mostly) backward compatible with the Bourne or POSIX sh syntax.
csh
and tcsh
which have a completely different syntax use /etc/csh.login
instead. fish
uses /etc/fish/config.fish
(regardless of whether it's in login mode or not).
zsh
's syntax is also not completely compatible with that of Bourne/POSIX, so by default, it doesn't read /etc/profile
. Its configuration files in login mode are /etc/zsh/zprofile
(or /etc/zprofile
depending on how zsh
was configured at build time) and /etc/zsh/zlogin
(or /etc/zlogin
) the latter being sourced after the zshrc
.
zsh
only sources /etc/profile
when in sh
or ksh
emulation in which case its syntax is much closer to that of POSIX sh than in the default zsh
emulation mode.
If you want zsh
to source /etc/profile
when in login mode, you'd need to add a source /etc/profile
in /etc/zsh/zprofile
, but you'd only want to do that when you have made sure the syntax of /etc/profile
and any other file it sources is compatible with that of zsh
.
Alternatively, you could add:
emulate sh -c 'source /etc/profile'
To /etc/zsh/zprofile
. Then /etc/profile
would be sourced in sh
emulation mode (and functions declared in there would also retain the sh
emulation mode).
Related videos on Youtube
nightsparc
Updated on September 18, 2022Comments
-
nightsparc over 1 year
I'm experiencing a strange behavior on some of our machines atm. At least, it seems strange to me and my colleagues and we didn't find any explanation for it :)
[edit 1]
Next paragraph seems to be wrong. See edit 2 at end.
We're using bash and zsh here. So, when SSHing into some of the zsh-default-machines (plainssh login@host
) which are configured to use zsh as default shell (withchsh -s /usr/bin/zsh
), the then-opened shell is an interactive but non-login shell, regardless if we're already logged in on the respective machine or not.In my understanding, SSHing into a machine should be starting a new user session on that machine, thus requiring the shell to be a login shell, right? Shouldn't that be the case for zsh, too?
When changing the default shell to bash on the machines, logging into the machine uses a login-shell.
Is this the normal behavior for zsh? Could it be changed? Or is it some misconfiguration?
[/edit 1][edit 2] Ok, according to the ZSH documentation you could easily test if it is a login shell or not:
$ if [[ -o login ]]; then; print yes; else; print no; fi
See: http://zsh.sourceforge.net/Guide/zshguide02.html
However, due to zsh man entry / documentation, zsh should source
/etc/profile
which in turn sources the scripts under/etc/profile.d/*.sh
. My question above originated in the fact, that the scripts are not sourced and thus most of our environment variables and system configuration stuff isn't properly initialized. However, as described above - when we're using bash as default shell,/etc/profile
and the scripts in the profile.d-folder are sourced.
[/edit 2][edit 3 - ANSWER] Thx @StéphaneChazelas for the answer in the comments below! It seems
zsh
is only sourcing/etc/profile
when running insh
/ksh
compatibility mode (see the respecitve man entry https://linux.die.net/man/1/zsh). As logging in via SSH doesn't trigger that compatibility mode,zsh
doesn't necessarily source/etc/profile
on it's own but have to be triggered via.zprofile
[/edit 3]System: OS: Ubuntu 18.04 zsh-5.4.2 with omz and some plugins activated.
Thank you!
-
nightsparc over 4 yearsThank you very much for the detailed answer! :)
-
nightsparc over 4 yearsOk, one more question out of curiosity ;) Do you also know why
/etc/profile
is sourced when opening a non-login shell (with terminator, xterm ...)? -
Stéphane Chazelas over 4 years@nightsparc, sourced by what shell? Note that some terminal emulators can be configured to start a login shell and some systems configure them like that by default.
-
nightsparc over 4 yearsSourced by
zsh
...maybe it's an Ubuntu (or Debian?) thing?/etc/profile
is sourced whenever I'm starting a terminal emulator, regardless which one I'm using (I triedgnome-terminal
,xterm
uandterminator
). Thats confusing, from your explanation above I'd assume that/etc/profile[.d]
is only sourced whenzsh
is forced to use the compatibility mode. Or, according toman zsh
when it is invoked assh
orksh
...but why are the terminal emulators are invoking it assh/ksh
? And is there a way to change it? -
Stéphane Chazelas over 4 years@nightsparc, what makes you think it runs /etc/profile? /etc/profile would probably have been sourced when you logged in. So environment variables would be inherited by the terminal emulator and by the shells started in there.
-
nightsparc over 4 yearsOh, right, of course. How could I not have thought of that :) thanks again!
-
nightsparc over 4 yearsOh, thanks for the flowchart and the informative links!
-
alper almost 3 yearsIn my
.zprofile
I haveexport TEST="hello"
. But when I doecho $TEST
it returns empty string, is it normal behavior? -
Simba almost 3 years@alper If you're on Linux, that's the normal behavior. Because the default shell opened in your terminal on Linux is a non-login shell. But on macOS, it's a login shell.
-
alper almost 3 yearsI am in Linux but on a remote machine that is connected via ssh. I was advices to carry all my export variables into
.zprofile
but when I did that they all return empth string and all are empty