LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This 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

Reply
 
Search this Thread
Old 01-04-2009, 06:22 AM   #1
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
Cool 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 11:58 PM.
 
Old 01-04-2009, 10:28 AM   #2
mk27
Member
 
Registered: Sep 2008
Distribution: fedora, gentoo, ubuntu
Posts: 148

Rep: Reputation: 23
I actually don't have this problem that much so I'm gonna keep my own prompt, but this is a neat idea.

I also don't do much shell programming and I have a quick question for you:

Code:
export PS1='\u:$(/usr/local/bin/variprompt.sh $COLUMNS)$ '
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?
 
Old 01-04-2009, 11:08 AM   #3
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 59
Quote:
Originally Posted by mk27 View Post
I also don't do much shell programming and I have a quick question for you:

Code:
export PS1='\u:$(/usr/local/bin/variprompt.sh $COLUMNS)$ '
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?
It's called command substitution. The form $(command) is a newer form of `command` (with backticks), which you may have seen before.
 
Old 01-04-2009, 12:35 PM   #4
antegallya
Member
 
Registered: Jun 2008
Location: Belgium
Distribution: Debian
Posts: 109

Rep: Reputation: 42
Hello,
thanks for the gift !

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 12:51 PM.
 
Old 01-04-2009, 07:01 PM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Original Poster
Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
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 View Post
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 07:23 PM.
 
Old 01-10-2009, 10:58 AM   #6
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Original Poster
Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
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.
 
Old 01-10-2009, 11:55 AM   #7
antegallya
Member
 
Registered: Jun 2008
Location: Belgium
Distribution: Debian
Posts: 109

Rep: Reputation: 42
Hello,
Code:
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.
 
Old 01-11-2009, 12:01 AM   #8
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Original Poster
Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
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.
 
Old 01-11-2009, 11:55 AM   #9
custangro
Senior Member
 
Registered: Nov 2006
Location: California
Distribution: Fedora , CentOS , Solaris 10, RHEL
Posts: 1,935
Blog Entries: 1

Rep: Reputation: 188Reputation: 188
I had a similar script...

Code:
#!/bin/ksh -fu
#
v_wd=$(pwd)
if [ ${#v_wd} -gt 30 ] ; then
  echo ${v_wd} | sed -e 's!\(...............\).*\(...............\)!\1 ... \2!'
else
  echo ${v_wd}
fi
#
Then I save it as /usr/local/bin/pwd30 and I have this as my PS1

Code:
export PS1="\h:\$(/usr/local/bin/pwd30)<\!>$ "
 
Old 03-21-2014, 07:04 AM   #10
antegallya
Member
 
Registered: Jun 2008
Location: Belgium
Distribution: Debian
Posts: 109

Rep: Reputation: 42
Hello !

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/"~"}"
 
  


Reply

Tags
bash, length, prompt, ps1, variable


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
BASH: instad of echo-ing, I just want to assing to a bash variable... how?? rylan76 Linux - Newbie 9 11-28-2008 09:46 AM
Bash read in variable length text records lynx81191 Programming 4 11-17-2007 09:53 PM
BASH length of file baks Programming 14 03-13-2007 10:52 PM
Zero-length bash .history file! revmyo Linux - Security 1 12-03-2005 09:09 PM
Variable length objects kamransoomro84 Programming 4 10-28-2004 01:56 PM


All times are GMT -5. The time now is 11:16 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration