do not export PS1 by default
Hello,
this system change proposal picks up where #12398 left off. There seems to be some contention around this area, so my proposal aims for as small a change as possible, while attempting to address concerns raised in the original ticket.
I've opened a merge request to show the changes I am proposing here. This is my first system change proposal for Alpine, so please do tell me if I'm doing it wrong.
As noted by @luke in the #12398 description and by @mirabilos in a comment, PS1 should not be exported. I agree with that: if PS1 is in the environment, it has undesirable effects eg. when a user starts a subshell that happens to have different semantics than their login shell for parsing PS1. In the following example with the current alpine-baselayout, login(1) has started busybox ash. If the user executes zsh, zsh uses the PS1 provided in environment, which results in a broken prompt:
login[2]: root login on 'pts/0'
9d55f85f6269:~# zsh
\h:\w\$
If PS1 is instead not exported to the environment, the subshell will get its PS1 value from its shell-specific initialization files (or from the compiled-in default value). With my proposed change, PS1 is no longer in the environment, and the above example looks like:
login[2]: root login on 'pts/0'
88c0be578710:~# zsh
88c0be578710#
Here, zsh's process-local PS1 ends up being set to '%m%# ', its compiled-in default fallback value, since zsh's shell-specific initialization files do not set it. For the login(1)-started ash, it has been set from /etc/profile as before (but is not exported).
The issue is not specific to ash or zsh -- all it requires is that the login shell interprets PS1 in some different way than the non-login shell.
Shell-specific defaults
You will notice that my MR also modifies the bash package. This is because the
current fallback-PS1 behavior for non-login shells is relying on PS1 in the
environment. If we only remove export PS1
, then a non-login bash will show
its default bash-5.2#
style prompt. To set an Alpine default for non-login
shells, I propose setting PS1 from shell-specific initialization files, such as
/etc/bash/bashrc
. My MR currently only implements this for bash, not other
shells; if the proposal is accepted, the implementation can be expanded to
other shells as desired.
As described in the original issue, using $ENV
instead to set a default PS1
is possible, but I feel using shell-specific files is a simpler solution (at
least for shells for which it's possible).
Allowing PS1 in the environment
While I personally don't think PS1 should ever be in the environment, @dalias objected to the proposal of re-setting PS1 in interactive subshells, appearing to prefer PS1 being exported (I hope I'm not misrepresenting their position).
As far as I can tell, the objection does not concern whether or not PS1 is exported by default, but whether or not PS1-from-environment takes effect in interactive non-login shells. It is possible to both not export PS1 by default, and for shell-specific default initialization files to honor an already-set PS1 from environment. I feel doing that should satisfy the original concerns;
To allow PS1 from the environment to take precedence, /etc/bash/bashrc
in my
proposal only sets PS1 if it has the built-in default value. (Side note:
instead of comparing to the default value, checking whether PS1 is currently in
the env, ie. exported, might be a bit more correct, but the only way I found to
check that in bash was parsing the output of export -p
, which was a bit too
complicated for my taste).
Addendum: low-effort survey of other distributions
I checked a few other distributions' default shell settings using their
official images from Docker hub, running env -i login -f root
to spawn an
interactive login shell, and printenv PS1
from there to see if PS1 was
exported in that login shell:
alpine:3.16.2 exported
amazonlinux:2.0.20220912.1 not exported
archlinux:base-20221002.0.91257 not exported
centos:7.9.2009 not exported
debian:11.5 not exported
fedora:36 not exported
gentoo/stage3:20221003 not exported
kalilinux/kali-last-release:latest not exported
oraclelinux:9 not exported
photon:4.0-20220930 not exported
ubuntu:22.04 not exported
So, alpine seems to be the odd one out -- among those above, no other distro exports PS1. The list of distributions tested is of course subjective; feel free to point out any counter-example distribution that does export PS1 from login shells by default.
I also had some non-Linuxes lying around: OpenBSD 7.1 and macOS 12.6 don't export PS1 either.
Addendum: sessions without login shells
I'd also like to point out that there can be user sessions that were started without a login shell, for example a session started from xrdp (there may be other examples; this was just easiest for me to verify) has a process tree like this:
25032 \_ /usr/sbin/xrdp-sesman -n
25035 \_ /usr/libexec/Xorg :10 -auth .Xauthority -config xrdp/xorg.conf -noreset -nolisten tcp -l
25034 \_ /bin/sh -e /home/foobar/startwm.sh
25042 | \_ xterm
25043 | \_ ash
25040 \_ /usr/sbin/xrdp-chansrv
neither the /bin/sh started by xrdp-sesman nor the ash started by xterm is a login shell, and thus PS1 is not set in the environment for this session at all. In the ash inside xterm, it is locally set to busybox ash default, not the alpine /etc/profile default.
This additional data point should demonstrate that setting PS1 is necessary for each interactive shell, instead of relying on it being in the environment (since nothing will put it in the environment if there is no login shell).