New Year's gift for you: A variable-length bash prompt
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
New Year's gift for you: A variable-length bash prompt
A Happy New Years! I have a small gift for you.
Are you tired of cd'ing to some deep-nested directory and having your command prompt stretch all the way across your window? Well, me too.
That's why, with the help of google and about 6 hours of trial and error, I finally succeeded in writing a script that will dynamically truncate the pathname in your prompt to whatever percentage of the screen you want.
Code:
#!/bin/bash
# This script takes the $PWD string and truncates it
# to a set percentage of the terminal width.
# It's designed to be used in the bash $PS1 prompt to keep it
# from taking up too much space, but it may be useful for
# other purposes too, of course. There may be minor variations
# in the actual length owing to rounding in the arithmetic
# functions. The most current version can be found here:
http://www.linuxquestions.org/questions/showthread.php?p=3396562#post3396562
# Usage: Put the script in a convenient location, such as
# /usr/local/bin, make it executable and set $PS1 in your
# .bashrc or similar file in this manner:
#
# shopt -s checkwinsize
# export PS1='\u:$(/usr/local/bin/variprompt.sh $COLUMNS)$ '
#
# Note the single quotes. Double quotes will not work.
# The shopt command ensures that the $COLUMNS variable is set
# in the terminal. If you don't include the $COLUMNS variable
# here, then the script will not be able to dynamically adjust
# to the width, and the target percentage setting will behave
# as a fixed-length string instead ($COLUMNS will default to
# 100).
# Set the desired width of the prompt below as the percentage
# of the total terminal width you want the path part of the
# prompt to take up. Remember that any other parts you add to
# the prompt (such as username) will take up additional space.
# Also be aware that this script is designed for reasonable
# numbers, and may act in unpredictable ways if the target
# and/or terminal width are very small. Target values under
# 20 are not recommended.
TARGETPCT=50
# (Hint: make it "$2" and you can set the target from
# within the PS1 prompt command instead, right after $COLUMNS.)
# The columns variable isn't readable from within the script.
# It must be fed in from outside. If missing, a default of
# 100 will be set.
COLUMNS=${1:-100}
# Modify the $PWD to collapse "$HOME" into "~". Simply
# replace this value with '$PWD' if this behavior is unwanted.
CURRENTDIR="${PWD/#$HOME/~}"
# Determine the number of characters in the
# modified $PWD string.
CURRENTLENGTH="${#CURRENTDIR}"
# Calculate the target length and the sizes
# of the starting and ending segments.
TARGETLENGTH="$((COLUMNS*TARGETPCT/100))"
FIRSTPART="$((TARGETLENGTH/3-3))"
LASTPART="$((CURRENTLENGTH-(TARGETLENGTH*2/3)))"
# Finally we compare the current length of the prompt
# to the target length and print the appropriate output string.
if [ "$CURRENTLENGTH" -le "$TARGETLENGTH" ]; then
# No modifications are necessary if less than the target length.
# Print the unmodified string.
echo "$CURRENTDIR"
else
# Very small target or column values can make "FIRSTPART"
# come out to zero or less. So test it to avoid throwing out
# an error, and set it to display only the first two characters
# of the string in such situations.
# Otherwise, print the desired truncated string.
if [ "$FIRSTPART" -gt "1" ]; then
echo "${CURRENTDIR:0:$FIRSTPART}...${CURRENTDIR:$LASTPART}"
else
echo "${CURRENTDIR:0:2}...${CURRENTDIR:$LASTPART}"
fi
fi
# All finished.
exit 0
Everything is fully documented, so please give it a shot. It's actually very simple all told, but it took me a long time to get all the bugs out. I'm all ears if you have any suggestions on how to improve it, especially in the arithmetical parts, which I don't have a lot of experience working with.
Let me know what you think of it!
-----
Edit: Updated script to fix $FIRSTPART<0 error.
Edit2: Replaced tabs with spaces and reduced the font size so that the layout formats better.
Edit3: Added a default for the $COLUMNS variable so that there's no error if not supplied, with the added bonus of allowing for a fixed-width setting. Also rewrote and rearranged the comments.
Edit4: Changed $FIRSTPART>0 to $FIRSTPART>1 to make behavior more consistent, plus other minor edits.
Last edited by David the H.; 01-10-2009 at 10:58 PM.
There's a problem in one case : if ( $COLUMNS < (900 / $TARGETPCT) ) then $FIRSTPART < 0 and you get a "substring expression < 0" error on line 49 (i.e : when $COLUMNS < 15 with the default settings).
To avoid this you may add a test like :
if [ "$((900 / $TARGETPCT))" -gt "$COLUMNS"]; then ...
I don't know what would be best to display in that case since it means that the terminal is very little...
[edit] Err okay the test could be
if [ "0" -gt "$FIRSTPART" ]; then ...
Last edited by antegallya; 01-04-2009 at 11:51 AM.
Thanks a lot for catching the error antegallya. I never thought about what would happen if the screen were that narrow! I've updated the script with your suggested fix. In the case that $FIRSTPART<0, it will now simply display only the first couple of characters.
Quote:
Originally Posted by mk27
How does this '$(somescript.sh)' work (or what is it called)? Can I use that method to set any env variable with the stdout from a shell script?
As telemachos explained, it's simply a way to use the output of one command inside another one. It's a bash built-in function, so I suppose it can be used just about anywhere.
But I can't really take the credit for the idea in this case. I got the basic idea and form from another page. I just re-wrote it to make it fully dynamic.
And no problem if you don't need it yourself. I really wrote it for my own pleasure and purposes. But I thought it might be something that others would find useful too.
Last edited by David the H.; 01-04-2009 at 06:23 PM.
I've cleaned the script up some more and made one functional change. Now if you fail to supply a $COLUMNS variable to the PS1 command, it will default to 100 columns. Not only does this avoid an error, but it also gives you the option to set the target as a fixed-length string.
I also did a little further testing with very small widths (both in target and columns), and there's still some strangeness going on. It won't give any errors, but it occasionally doesn't work as expected. One of the first two characters sometimes won't display, for example. But since these are minor problems that most people wouldn't normally encounter, I'm not going to bother trying to work around them. I recommend simply not setting the number lower than about 20-25 if you're worried about consistent behavior.
One of the first two characters sometimes won't display, for example.
It occurs when FIRSTPART=1 who is greater than 0 so you're substituting from 0 to 1 and you get only the first character. If you always want to display at least the two first characters just change the test to :
Code:
if [ "$FIRSTPART" -gt "1" ]; then ...
And if I did not make mistakes it occurs when 1200<=COLUMNS*TARGETPCT<1500 and CURRENTLENGTH>12.
Thanks again. That makes sense. I should've thought of that. You certainly are much better at understanding why this stuff works than me. My style is just to hammer away until I get something to work. Having to work out this math stuff makes my head hurt.
Ok, so the last change for now will be to change the test to >1. I could alternately just tell it to display only one character, but I personally think two looks better.
That wasn't the only odd thing going on, but I think the others can mostly be attributed to mathematical rounding, which can be relatively extreme when the numbers are small. Numbers less than 20 or so will probably always show a bit of strangeness. It's all minor stuff in any case.
Digging up this old thread just to say that it seems that bash now expands tilde in the replacement string construct "${PWD/#$HOME/~}". That means this should be patched :
Code:
@@ -54,7 +54,7 @@
# replace this value with '$PWD' if this behavior is unwanted.
-CURRENTDIR="${PWD/#$HOME/~}"
+CURRENTDIR="${PWD/#$HOME/"~"}"
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.