RFC - Korn shell prompt

Hi,

I am learning shell scripting for the first time. I use AT&T Korn Shell, Version AJM 93u+ 2012-08-01, compiled from source on NetBSD.

So far I have managed to set up what I think is a useful and pleasing shell prompt, which can be seen in the image attached to this post.

The prompt is a multi-line prompt, as follows:

Line 1 (reverse video) shows the TERM variable, together with TTY, SHELL, and the date and time as it was when the prompt was updated.
(The print -f statement formats this line so that the text is right-aligned and the reverse-video bar takes up the whole width of the terminal, even if it is resized. It uses the COLUMNS variable to achieve this.)

Line 2 shows the host I am connected to (obscured for security).

Line 3 shows the job number and current working directory.

Line 4 shows the user name and the prompt itself.

I have just one problem: unless I symlink /bin/ksh93 to /bin/sh (the default shell on NetBSD) I get errors about "bad substitution". I am certain my prompt is causing this problem, but I still don't know enough to say what is wrong. Would somebody be so kind as to look at my PS1 and tell me where I am going wrong, and where I can improve it? I have learned quite a bit about if...then and case statements while learning how to do this prompt, but I am still unclear about brackets, single quotes and double quotes.

The following is the relevant part of my .kshrc file. I have split the PS1 lines for readability but they are all on one line in the file.

                                                                         
ttyhere=$(tty | sed -e "s:/dev/::")                                               
timenow=$(date +"%H:%M %Y%m%d")                                                   
currshell=$(print "$SHELL" | sed -e "s:/bin/::")                                  
                                                                                  
PS1='$(print -f "\n\E[1;7m%${COLUMNS}s\E[0m\n" "[$TERM] \
[$ttyhere] [$currshell] [Time at prompt: $timenow] "; \
print "[$(hostname)]"; \
print -n "[\E[1;36m!\E[0m]"; \
if [[ "${PWD#$HOME}" != "$PWD" ]] then; \
print "[\E[1;35m~${PWD#$HOME}\E[0m]"; \
else; print "[\E[1;35m$PWD\E[0m]"; fi; \
if [[ $(id -u) -ne 0 ]] then; \
print "[\E[1;36m$(id -un)\E[0m]$ "; \
else; print "[\E[1;35m$(id -un)\E[0m]# "; \
fi;)' ;;

Try changing to:

ttyhere=$(tty)
ttyhere=${ttyhere##*/}                                               
timenow=$(date +"%H:%M %Y%m%d")                                                   
currshell=${SHELL##*/}                                  
                                                                                  
PS1='$(print -f "\n\E[1;7m%${COLUMNS}s\E[0m\n" "[$TERM] \
[$ttyhere] [$currshell] [Time at prompt: $timenow] "; \
print "[$(hostname)]"; \
print -n "[\E[1;36m!\E[0m]"; \
if [ "${PWD#$HOME}" != "$PWD" ];then \
print "[\E[1;35m~${PWD#$HOME}\E[0m]"; \
else print "[\E[1;35m$PWD\E[0m]"; fi; \
if [ $(id -u) -ne 0 ];then \
print "[\E[1;36m$(id -un)\E[0m]$ "; \
else print "[\E[1;35m$(id -un)\E[0m]# "; \
fi)'

The main problem was the missing ; between ]] and then in two places in your if statements.

You have some other ; s that aren't needed, but they wouldn't keep your script from working.

You can use [ expression ] instead of [[ expression ]] with the expressions you're using, but either will work with a 1993 or later version of ksh .

The changes to ttyhere and currshell are just performance improvements.

Keep the ;; I removed at the end of this if it is code that has been extracted from the end of a choice in a case statement; otherwise, it is likely to be a syntax error.

1 Like

Thank you Don! I am hugely embarrassed to tell you that it now turns out my "bad substitution" problem was down to a bad alias. When I substituted your prompt for mine I still had the error, so I looked more closely at the rest of my .kshrc and .profile and commented out bit by bit till I narrowed it down to the following rogue statement, which is meant to return the version of ksh I am running:

alias kv="print ${.sh.version}"

Dear oh dear. So sorry! But I am happy you've cleaned up my prompt. I'm now going to go off and figure out what you did with my TTY and SHELL variables.

This one has me perplexed. I've looked through the prompt and can't really put my finger on the ; s which could be removed. Edit: I see them now, after the else keywords and fi.

Done.

haha! Well spotted. Indeed I do have a case statement, which accommodates Emacs: when I open a shell inside emacs TERM is reported as "dumb", and the first line of the prompt is slightly different, so I just use this case statement to fix the issue that arises. A learning exercise for me really.
Once again, thank you so much for taking the time to fix this for me! Now off for more learning!

:slight_smile: