LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Fixing shell prompts (https://www.linuxquestions.org/questions/slackware-14/fixing-shell-prompts-4175472234/)

GazL 08-05-2013 04:11 PM

Fixing shell prompts
 
Slackware's /etc/profile contains the following section relating to shell prompts:
Code:

# Set a default shell prompt:
#PS1='`hostname`:`pwd`# '
if [ "$SHELL" = "/bin/pdksh" ]; then
 PS1='! $ '
elif [ "$SHELL" = "/bin/ksh" ]; then
 PS1='! ${PWD/#$HOME/~}$ '
elif [ "$SHELL" = "/bin/zsh" ]; then
 PS1='%n@%m:%~%# '
elif [ "$SHELL" = "/bin/ash" ]; then
 PS1='$ '
else
 PS1='\u@\h:\w\$ '
fi
PS2='> '
export PATH DISPLAY LESS TERM PS1 PS2

There are a couple of problems with this approach. The first is that the value of $SHELL doesn't necessarily reflect the shell that is running the /etc/profile file. The second issue is that the PS1 and PS2 are exported, which means that if you were to start a non-login ksh or ash shell from within bash, or even a non-login bash shell from ksh they will inherit the incompatible shell prompt from the parent shell's environment and it won't display correctly.

While altering the code to use $0 rather than $SHELL and simply not exporting the PS1/2 would stop the incompatible inheritance issue, it would result in no inheritance at all and a default prompt in non-login shells (which IMO would still be a better choice than the brokenness we currently have but isn't ideal). To make everything nice and tidy I think the prompt stuff needs to be moved out of /etc/profile and into bashrc and equivalents for the other shells, which would make everything work as it should.


So, what I'm suggesting:

1) Remove the existing prompt setting code (including the export of PS1/2) from /etc/profile.

2a) Add a /etc/skel/.bash_profile (to run .bashrc for login-shells):
Code:

case $- in
*i* )  # Interactive shell
      if [ -f ~/.bashrc ]; then
          source ~/.bashrc
      fi
      ;;
esac

2b) Add a /etc/skel/.bashrc (to set PS1/2, aliases and/or optionally run a system wide /etc/bashrc):
Code:

[ -f /etc/bashrc ] && source /etc/bashrc

########################################################################

PS1='\u@\h:\w\$ '

alias ls='ls --color=auto --group-directories-first'

Then, to make something similar happen with the non-bash shells...
3a) Add a /etc/shinit file along the lines of:
Code:

# /etc/shinit  Shell environment file

#  Shell environment file for tradition bourne family shells:
#    ash, ksh, pdksh, bash (when invoked with -posix or as 'sh').
#
#  To be invoked its path must be specifed in the 'ENV'
#  environment variable.
#
#  Unlike /etc/profile, this file will also be invoked for
#  non-login shells and is therefore a good place to specify
#  aliases and PS prompts.


case $- in
*i* )  # Ensure we only run in 'interactive' shells.
      case $0 in
      -pdksh|pdksh|*/pdksh)
                PS1='! $ '
                ;;
      -ksh|ksh|*/ksh)
                PS1='! ${PWD/#$HOME/~}$ '
                VISUAL=emacs      #  ksh93 Visual editing mode
                                  #    VISUAL=emacs|gmacs|vi
                ;;
      -sh|sh|*/sh|-ash|ash|*/ash)
                PS1='$ '
                ;;
      esac
      ;;
esac

(I've also incorporated the ksh93 VISUAL setting from /etc/profile into this so that can also be removed from /etc/profile.)

3b) Add the following to /etc/profile in order to make /etc/shinit run:
Code:

# Set Shell environment file for traditional bourne shell family:
#  ash, ksh, pdksh, bash (when invoked with -posix or as 'sh')
ENV='/etc/shinit'
export ENV

End result: each shell gets the correct prompt no matter whether it is a login or non-login shell or whether it is started from within a different shell type.

The only one I haven't included in this is zsh as I am unfamiliar with it's inner workings, but I suspect /etc/zshenv might be the correct place to set it's own PS1 in a similar manner.

If you only use bash, then the PS string stuff probably won't bother you, but moving the alias definitions to bashrc would have the advantage of making them available in non-login shells so there is still something to be gained.

Anyway, those are my thoughts and it's how I have my box configured at present.

Over to y'all for comments/suggestions...

adelabarra 08-06-2013 06:44 AM

Dear GazL:
I use Slackware with xfce. (and kernel 2.6.10)
Don't know why when I enter the terminal from xfce, the prompt doesn't appear and I don't know where I am.
If I type export PS1= "\W", everything is OK.
How can I do to make it permanent?

Regards.

Alejandro.

GazL 08-06-2013 07:01 AM

The safest bet is to add .bashrc and .bash_profile (as I described in 2a and 2b above) to your home directory. That way it should work in a desktop environment independent manner.

tronayne 08-06-2013 09:12 AM

All my systems are defaulted to KornShell (I just don't really care to use BASH) and terminals on all of them are configured as log in shells in Xfce (KDE is installed -- do like some of the utilities, don't like the overhead); matter of fact all shells are configured as log in shells no matter what window manger I use.

I do the prompt with a file, /etc/profile.d/ksh.sh (which is simply an edited part of /etc/profile):
Code:

#!/bin/sh
#
# Set the HOST environment variable
export HOST="`uname -n`"
# Set ksh93 visual editing mode:
if [ "$SHELL" = "/bin/ksh" ]; then
#  VISUAL=emacs                # ugh
#  VISUAL=gmacs                # double ugh
  VISUAL=vi                # ah, elegance
fi
# Set a default shell prompt:
#PS1='`hostname`:`pwd`# '
# Do these anyway in case sombody uses a different shell
if [ "$SHELL" = "/bin/pdksh" ]; then
 PS1='! $ '
elif [ "$SHELL" = "/bin/ksh" ]; then
 PS1='${HOST}-${USER}-${PWD}: '
elif [ "$SHELL" = "/bin/zsh" ]; then
 PS1='%n@%m:%~%# '
elif [ "$SHELL" = "/bin/ash" ]; then
 PS1='$ '
else
 PS1='\u@\h:\w\$ '
fi
PS2='> '
export PS1 PS2

The above makes a terminal window prompt look like
Code:

fubar-trona-/home/trona:
and, because all systems are configured identically, I always know what box I'm on when connected with ssh to any one (or all) of them; one keyboard to rule them all, baby.

I also have, in each user home directory, .profile, .kshrc and .exrc. The .profile sets "useful" environment variables specific to the individual user:
Code:

fubar-trona-/home/trona: cat .profile
#        set up default columns and lines
COLUMNS=80
LINES=40
export COLUMNS LINES
#        set up default group
GRPNAME=`groups | cut -d' ' -f1`
export GRPNAME
#        set up a good-size history
HISTSIZE=1000
export HISTSIZE
#        set up the ksh environment
ENV=${HOME}/.kshrc
export ENV
#        set up CVSROOT
CVSROOT=:pserver:trona@fubar.com:/usr/local/cvsroot
export CVSROOT
#        change the PATH a little
export PATH=.:${HOME}/bin:${PATH}
export INSTALL_BASE=${HOME}
export LLDATABASES=${HOME}/LifeLines:.
export LLPROGRAMS=.:/usr/local/share/lifelines
#        make COLUMNS and LINES the screen size
eval `resize`

The COLUMNS and LINES are handy for curses forms; default to 80x40 (from the Goode Olde Days, that) and updated by the eval `resize` at the end; saves some trouble now and again. The other stuff are for compatibility with some specific work I do.

I also set, for me only, the current working directory as first on ${PATH} followed by my ${HOME}/bin; I'm well aware of the hazards of so doing and have been doing it for about 30 years and don't need any argument about it: It's my party and I'll cry if I want to.

~/.kshrc simply sets some aliases I like:
Code:

fubar-trona-/home/trona: cat .kshrc
alias lc='/usr/bin/clear; /bin/ls ${LS_OPTIONS} -aCF'
alias ll='/bin/ls ${LS_OPTIONS} -al'
alias cls='clear'
alias hi='history -${LINES}'
alias rs='eval `resize`'

And ~/.exrc simply sets defaults that I like for vi:
Code:

fubar-trona-/home/trona: cat .exrc
set autoindent showmode showmatch

As far as I know, ${SHELL} gets set by login (from the log in shell in /etc/passwd) and is then used in /etc/profile so I don't see any problem with that. All the admin accounts are /bin/false (or special purpose like shutdown and halt, one or two others) and you're not supposed to be fiddling with those anyway so I don't see any problem there (you need to do some administration, you do it with su - far as I know and if you don't know what you're doing you shouldn't ought to be doing it anyway, eh?).

Defining terminal windows as log in shell does no harm -- you execute su -, you get root's environment. When you exit, you're back to your own environment (su - forks and executes in a new shell and when it exits that environment is gone). Simply demonstrated with
Code:

fubar-trona-/home/trona: su -
Password:
fubar-root-/root: whence -v ntpq
ntpq is a tracked alias for /usr/sbin/ntpq
fubar-root-/root: ^D
fubar-trona-/home/trona: whence -v ntpq
-ksh: whence: ntpq: not found

Same thing happens if you su - userid -- you get a forked-and-exec'd new shell, it is gone when you exit.

So, basically, I don't really see the problem with /etc/profile -- especially if you add custom files in /etc/profile.d, which, for example, would include things like Apache Ant, Apache Maven, Apache Tomcat, Java (jdk.sh and jdk.csh) and one that I add for the Generic Mapping Tools, gmt.sh, which sets environment variables for it -- that's what /etc/proifle.d is for, no need to mess with the default /etc/proifle (as in the Goode Olde Days when that was your only choice for system-wide settings).

Good thinking, but I'm not sure there's actually a problem.

GazL 08-06-2013 09:52 AM

Quote:

Originally Posted by tronayne (Post 5004032)
A
As far as I know, ${SHELL} gets set by login (from the log in shell in /etc/passwd) and is then used in /etc/profile so I don't see any problem with that.

$SHELL does indeed get set by login, and it gets set to the value of the users default shell specified in /etc/passwd. The problem comes when you launch a login shell that is different to your default shell. For example having a default shell /bin/ksh, but then running "bash -l" from the ksh command-line after you login. 'bash -l' will run /etc/profile but $SHELL will still be '/bin/ksh' so it will be given the incompatible ksh PS1 string.

To be fair, this is probably a corner-case, as most people won't be using the -l option to start a login shell, and are especially unlikely to do so for a shells other than their default. I think the exporting of PS1/2 is what I object to most (but I guess that actually suits people who only ever use bash, though it does cause problems for the other shells).

I think that ideally I'd like to see /etc/profile not contain anything other than tradition 'sh' compliant stuff - even if this would mean having to stick with the less feature-full default '#' prompt out of the box.


Thanks for posting your setup. I found it interesting. :)

P.S. I'd forgotten about 'su', so using $0 rather than $SHELL isn't going to work in all situations either. I think the last time I looked at this stuff I ended up doing a test -n "$BASH_VERSION" to reliably identify a bash shell, but not all shells have a unique environment variable like that to select on. Given this added complexity, I think I'm leaning even more to not setting the prompt at all in /etc/profile and letting it default.

tronayne 08-06-2013 10:24 AM

Huh.

Yup, see what you mean, but also see that it's highly unlikely that somebody would be switching back and forth (you learn one, the others are just unnecessary confusion -- think C-Shell here, what a mess that is). Absolutely, positively have to run a shell program in some other shell? That's what pound-bang is for, eh?.

There was (and still is) nothing wrong with Bourne, David Korn made it better (a lot better, IMHO). Berkeley went off in the blue somewhere or 'toher (what were those guys smoking when they came up with C-Shell?). BASH, well, Bourne + Korn + ... well, I dunno (and they seem to be unable to leave the damned thing alone!).

Anyway, getting off that tangent, some good thinking.

GazL 08-06-2013 11:09 AM

I know what you mean about csh. Never got on with that.

Anyway, for the sake of completeness, here's a revised /etc/shinit that takes care of the '-su' issue it was missing before:

Code:

# /etc/shinit  Shell environment file

#  Shell environment file for tradition bourne family shells:
#    ash, ksh, pdksh, bash (when invoked with -posix or as 'sh').
#
#  To be invoked its path must be specifed in the 'ENV'
#  environment variable.
#
#  Unlike /etc/profile, this file will also be invoked for
#  non-login shells and is therefore a good place to specify
#  aliases and PS prompts.


case $- in
*i* )  # Ensure we only run in 'interactive' shells.
      case "$0" in
          -pdksh|pdksh|*/pdksh) shell='pdksh' ;;
          -ksh|ksh|*/ksh) shell='ksh' ;;
          -ash|ash|*/ash) shell='ash' ;;
          -sh|sh|*/sh) shell='sh' ;;
          *) shell="${SHELL##*/}" ;;  # -su and any unknown shells.
      esac

      case "$shell" in
      pdksh)  PS1='! $ '
              ;;
      ksh)    PS1='! ${PWD/#$HOME/~}$ '
              VISUAL=emacs  #  ksh93 Visual editing mode
                              #    VISUAL=emacs|gmacs|vi
              ;;
      ash|sh) PS1='$ '
              ;;
      esac
      ;;
esac

unset shell

Whether making this work correctly is worth all the effort I'm not sure, but it's an interesting exercise.


BTW, While we're on the subject:
Any reason /bin/sh is not in /etc/shells?

adelabarra 08-06-2013 05:28 PM

Thanks to all!

I'll come back when I finish an try all this.

Regards.

Alejandro

elyk 08-06-2013 10:46 PM

+1 for not exporting $PS1 and $PS2.

+1 for providing a default .bash_profile and .bashrc, and for setting up .bash_profile to source .bashrc.

I assume that all of these shells set up their own default prompt if we leave $PS1 alone. Is there any reason why we override it globally? To me it seems like it should be set on a per-user basis, so in .bashrc or equivalent for their shell of choice.

GazL 08-07-2013 04:04 AM

The shells will default to their own prompt strings: most of which are not particularly helpful (e.g. bash uses "bash-4.2$"), but as I said in the first posting I'd rather have that than have the currently broken behavior we see from exporting PS1/2.

My guess is that they are overridden just to set a more useful system-wide default prompt, and exported so that they inherit down to child shells. Unfortunately this solution, though simple is a bit hit-n-miss and as shown above has side effects.


All times are GMT -5. The time now is 03:03 AM.