Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Create a fixed-length bash shell prompt UNIX
This tip is stolen from instructions in the Bash Prompt HOWTO. It's not terribly innovative, and most Unix distributions (MacOS X included) come with a tolerably decent default prompt; consequently, even many very experienced Unix users don't know a lot about prompt configuration (I certainly didn't). But if you compile and install bash on MacOS X, you'll find that you are left with a very unsatisfactory default prompt. It was this problem that led me to sniff this information out.

This tip solves the dilemma of whether to use \W (current directory without path) or \w (complete path to current directory) in the prompt. On the one hand, \W doesn't contain the path (am I in /etc or /usr/local/etc?), but \w (which contains the path) can monopolize the command line. The solution: Include only the last x characters of the current working directory.

This tip will work swimmingly with bash, and maybe someone can explain how to do the same thing with tcsh in the replies (I'm a bash partisan myself, and I heartily recommend it to anyone who has to use the shell regularly). Read the rest of this article for instructions on creating a fixed-length bash shell prompt.

Include the following in your /etc/profile or ~/.profile file (according to your preference):
function prompt_command {
# How many characters of the $PWD should be kept
local pwd_length=23
if [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="$(echo -n $PWD | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"
else newPWD="$(echo -n $PWD)"
fi
}

PROMPT_COMMAND=prompt_command

export PROMPT_COMAND
Now, use $newPWD in place of \W or \w in your PS1 environment variable. For example, when I'm in my home directory, my prompt looks like this:
[username@hostname:/Users/username]$
And when I'm in /Users/username/Documents/Downloads, my prompt looks like this:
[username@localhost:ame/Documents/Downloads]$
Bonus: If you want to have a universal prompt definition (i.e., you want to place it in /etc/profile, and still want to get $ for users and # for root, then you can add the following to /etc/profile:
if [ "$UID" = "0" ]
then TERMINUS="#"
else TERMINUS="\$"
fi
Then, put $TERMINUS at the end of your PS1 definition. My prompt is defined as follows:
PS1="[\u@\h:$newPWD]$TERMINUS "
export PS1
This gives me a fixed number of characters for the PWD listing so that it doesn't monopolize my screen. It also gives me a $ for users and # for root.
    •    
  • Currently 0.00 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (0 votes cast)
 
[8,032 views]  

Create a fixed-length bash shell prompt | 22 comments | Create New Account
Click here to return to the 'Create a fixed-length bash shell prompt' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
For the zsh users in the audience...
Authored by: sabi on Dec 22, '01 03:22:17AM

This is my prompt:

prompt="{%U%n#%l@%m:%h%u} %30<...<%~%#"

which produces something like this:

{nicholas#p4@rattle:3} ~% cd /System/Library/Frameworks/
{nicholas#p4@rattle:4} /System/Library/Frameworks%cd LDAP.framework/
{nicholas#p4@rattle:5} ...y/Frameworks/LDAP.framework%

Of course, replace the 30 with another number if you want to truncate at a different length.

When I can put most everything else in the window title, I have an abbreviated version:

prompt="[%U%l:%h%u] %~%#"

This one doesn't do truncation as I haven't found it necessary, but it wouldn't be hard.



[ Reply to This | # ]
tcsh prompt
Authored by: serversurfer on Dec 22, '01 04:24:31AM

Here's what I use.

set prompt="%S%P%s%n@%m%c03 %B%h%b%# "

This shows

2:29:07surfer@stella~ 6% cd /System/Library/Frameworks/LDAP.framework/Versions/A
2:29:08surfer@stella/<3>LDAP.framework/Versions/A 7%

The <3> represents the number of hidden directories. This is set with the %c03 section of the prompt definition. The 3 means show the last three elements of the path, and the leading 0 tells tcsh to show the number of hidden directories.
The 6 and 7 before my prompt is the history number of the command I'm about to execute. It's so you can easily recall a command later, but I don't really know how, I just thought it was cool.

There's also some color and highlighting commands in there that don't show up here. Also notice that I have a trailing space before the final quote in my prompt increase readability on the command line.
More info can be found if you 'man -c tcsh' then Apple-F for %c[[ (scroll back a bit to read the intro.)



[ Reply to This | # ]
tcsh prompt
Authored by: pmccann on Dec 22, '01 11:21:00AM

You mean you don't know how to recall these commands "down the track"? To get the command issued after the %6 prompt just enter

!6

any time in the current session and so forth. History is very nice, and even nicer if you "merge" the histories from all the different terminal windows that you have open. (Otherwise the most recently closed clobbers the existing .history file. Merging interleaves the commands with what's there already. There's a really nice article on daemonnews about tcsh (and csh) that explains a lot:

http://www.daemonnews.org/200112/csh_tcsh_part1.html

Well worth a read, and remembering to venture back for parts 2 and 3.

Regards,
Paul



[ Reply to This | # ]
Spiffy!
Authored by: serversurfer on Dec 23, '01 07:08:11PM

Thanks a lot! I was wondering how to recall these. I found the 'show history#' bit in the 'prompt' section of the tcsh man and , while I had no idea how to use it at the time, it seemed elite, and I figured I would come across the data eventually. ;)
I kind of like having separate histories for each shell, but my friend was just wishing he could merge them. I'll pass that link along to him, and offer his thanks in absentia.



[ Reply to This | # ]
Another bash prompt trick
Authored by: dougc on Dec 22, '01 11:10:55AM

This is a cool tip, but I've never liked so much stuff in the prompt, so I split it up and put some into the title bar. My prompt is simply two lines:

export PS1='$USER@$HOST:{!}=>'

This line should be obvious. It will set your prompt to user@host and also display the command number. The command number is handy for executing a previous command. For example, !25 will execute command 25 in the history.

export PROMPT_COMMAND='echo -n "^[]1;$PWD^G"'

This line is a little tricky. What is not obvious are the characters in between the " ". The first character is a literal escape character. It is input in vi by typing ^V then pressing the escape key. These two keystrokes will produce the two characters ^[ . The next characters are just regular characters: ]1'$PWD . But the last character is a literal ^G. It is entered the same way as the escape, in vi type ^V then ^G. What all of this work will get you, is the current path (or whatever $PWD is set to) in the title bar of your terminal window.



[ Reply to This | # ]
Another bash prompt trick
Authored by: dlandrith on Dec 22, '01 11:54:35AM

This one rocks. Definitely better than what I posted.



[ Reply to This | # ]
Another bash prompt trick
Authored by: dougc on Dec 24, '01 06:28:27PM

Naw... It's nothing really. This is just old xterm stuff that I've never forgot.

BTW, thanks for pushing bash. I don't know how anyone can use csh based shells any more.



[ Reply to This | # ]
Setting the Terminal window title from tcsh
Authored by: thinkyhead on Dec 30, '01 05:18:54AM
To set the title of the Terminal window from tcsh you do pretty much the same thing, except tcsh uses an alias to do its magic: alias cwdcmd 'echo -n "^[]1;$PWD^G"'

[ Reply to This | # ]
Another bash prompt trick
Authored by: packy on Jan 29, '02 02:08:10PM
It's even easier than you guys are making it out to be. I set my bash prompt with the following:
PS1="\[\033]0;\u @ \h: \w\007\]\$ "
This sets my widow title to be "<username> @ <hostname>: <path> (ttyp?)".

[ Reply to This | # ]
two-line prompt
Authored by: snoozer on Dec 22, '01 01:18:17PM
I split my bash prompt across two lines (actually three, if you count the blank spacer). This sacrifices some vertical screen space in order to see all the information I want. These days terminal windows are resizable and have scrollbars, so it's not like I have to cram as much as I can into an 80x25 screen. Here's my prompt:
export PS1="n[w]n#: "
It produces results like this:
[~/Documents/programming] 5: cd FlipViewApp [~/Documents/programming/FlipViewApp] 6:
So I get a complete path name *and* plenty of space to type commands. If you've enabled your root account (as I have), you can replace the ":" with a "#" in root's bash prompt. This way you can always tell at a glance whether you're su'ed. (Note: for some reason the root account wants to use .bashrc whereas my regular user account wants to use .bash_profile. No idea why.) --Andy

[ Reply to This | # ]
$TERMINUS
Authored by: snoozer on Dec 22, '01 01:23:25PM

Oops -- dlandrith, I didn't see your $TERMINUS trick. That's what I should do.

--Andy



[ Reply to This | # ]
Duplicate default tcsh prompt in bash
Authored by: DimpledChad on Dec 26, '01 11:43:06PM
I personally have grown accustomed to the default tcsh prompt in OSX. Therefore, when I switched to bash, I wanted to duplicate that configuration. Here is what I came up with:
from my .bashrc: export PS1="[h:w] u$TERMINUS "
This gives the desired result:
[localhost:~] username%
For $TERMINUS to display the correct character, you need to put this in your /etc/profile:
if [ "$UID" = "0" ] then TERMINUS="#" else TERMINUS="$" fi


[ Reply to This | # ]
No need for $TERMINUS
Authored by: thinkyhead on Dec 30, '01 06:04:49AM

... Just use the special character backslash-$ as described in the bash manpage. Your example becomes this instead:

export PS1="[backslash-h:backslash-w] backslash-u backslash-$ "



[ Reply to This | # ]
Typo in original post
Authored by: clh on Dec 30, '01 05:54:34PM

The line that reads ...

export PROMPT_COMAND

... misspells "COMMAND"



[ Reply to This | # ]
Can't get this to work!
Authored by: clh on Dec 30, '01 09:11:16PM

I tried what the original post suggested, but my prompt does not dynamically change as I navigate directories.

Here's some debug info:

[chap@sudi:/Users/chap]$ echo $PROMPT_COMMAND
prompt_command
[chap@sudi:/Users/chap]$ prompt_command
[chap@sudi:/Users/chap]$ echo $newPWD
/Users/chap
[chap@sudi:/Users/chap]$ echo $PS1
[u@h:/Users/chap]$
[chap@sudi:/Users/chap]$ cd shex
[chap@sudi:/Users/chap]$ pwd
/Users/chap/shex

In .bashrc is the line

PS1="[u@h:$newPWD]$ "

So it appears that $newPWD is being substituted immediately at shell startup, rather than prior to displaying each prompt, the way w is. In order for this to work, I would think that PS1's value would have to remain "[u@h:$newPWD]$ " throughout the shell session.

Any thoughts?

PS - no clue how to make backslashes appear in the above - just assume it's there in front of u, w, h.



[ Reply to This | # ]
Correction to original post?
Authored by: clh on Dec 31, '01 02:26:54AM

For the solution in the original post to work, I believe you need to set PS1 *inside* the prompt_command function.

The final lines of the function should read

...
if [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="$(echo -n $PWD | sed -e "s/.*(.{$pwd_length})/1/")"
else newPWD="$(echo -n $PWD)"
fi
PS1="[u@h:$newPWD]$ " ## <-- add this line to recompute PS1
}

Another solution, which doesn't require burying the assignment of PS1 inside a function, is to modify prompt_command as follows:

...
if [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="$(echo -n $PWD | sed -e "s/.*(.{$pwd_length})/1/")"
else newPWD="$(echo -n $PWD)"
fi
echo $newPWD ## <-- "return" the newly-computed CWD
}

Then set PS1 as follows

PS1="u@h:$(prompt_command)$ " ## <-- invokes prompt_command and inserts CWD

You don't need to use the PROMPT_COMMAND variable with this method.

Well, I'm new to this forum and I haven't learned how achieve WYSIWYGedness, so I'm sure this will be missing scads of backslashes when you read it on the web. But anyway, I *think* the original post was not quite correct.

semicolon hyphen close-parenthesis



[ Reply to This | # ]
Saving PS1, don't change it :)
Authored by: cheako on Sep 15, '03 05:43:33AM

This is what I have...

echo $PROMPT_COMMAND | grep -qe 'How many characters' || {
PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND';
'}' {
# How many characters of the $PWD should be kept;
if [ "$lastPWD" != "$PWD" ];
then lastPWD="$PWD";
tmpPWD="$(echo -n "$PWD" |
sed -e '\''s:^'\''"$HOME"'\'':~:'\'')";
pwd_length=41;
pwd_prefixlength=11;
if [ $(echo -n "$tmpPWD" | wc -c) -gt $pwd_length ];
then newPWD="$(echo -n "$tmpPWD" |
sed -e '\''s:\(.\{'\''$pwd_prefixlength'\''\}\).*\(.\{'\''$((
$pwd_length - $pwd_prefixlength - 2 ))'\''\}\):\1..\2:'\'')";
else newPWD="$tmpPWD";
fi;
unset pwd_length pwd_prefixlength;
fi; # tmpPWD is not newPWD;
}'; # Out of singel quoted string hell.
# Export is not needed, but PS1 is and this will be used there.
export newPWD="$(echo -n "$PWD" | sed -e 's:^'"$HOME"':~:')"
# Force newPWD update.
lastPWD=..Yo..
}; # grep for 'How many characters' in PROMPT_COMMAND;

# All of this should allready be set to a good default, make them better.
[ "$PRO_UID" ] || PRO_UID=$(id -u)
if [ "$PRO_UID" -eq 0 ]
then PS1='\[\017\]\h:\[$newPWD\]\$ '
else PS1='\[\017\]\u@\h:\[$newPWD\]\$ '
fi
unset PRO_UID

# The \017 fixes the \016 bug :) echo -e '\016' for deatails :P



[ Reply to This | # ]
Correction to original post?
Authored by: clh on Dec 31, '01 04:16:36AM

For the solution in the original post to work, I believe you need to set PS1 *inside* the prompt_command function.

The final lines of the function should read

...
if [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="$(echo -n $PWD | sed -e "s/.*(.{$pwd_length})/1/")"
else newPWD="$(echo -n $PWD)"
fi
PS1="[u@h:$newPWD]$ " ## <-- add this line to recompute PS1
}

Another solution, which doesn't require burying the assignment of PS1 inside a function, is to modify prompt_command as follows:

...
if [ $(echo -n $PWD | wc -c | tr -d " ") -gt $pwd_length ]
then newPWD="$(echo -n $PWD | sed -e "s/.*(.{$pwd_length})/1/")"
else newPWD="$(echo -n $PWD)"
fi
echo $newPWD ## <-- "return" the newly-computed CWD
}

Then set PS1 as follows

PS1="u@h:$(prompt_command)$ " ## <-- invokes prompt_command and inserts CWD

You don't need to use the PROMPT_COMMAND variable with this method.

Well, I'm new to this forum and I haven't learned how achieve WYSIWYGedness, so I'm sure this will be missing scads of backslashes when you read it on the web. But anyway, I *think* the original post was not quite correct.

semicolon hyphen close-parenthesis



[ Reply to This | # ]
What Version of bash are you using?
Authored by: dlandrith on Jan 01, '02 12:11:17PM

With the exception of the export statement that contains the type, this function is exactly (cut and pasted from my profile) what I use and it works perfectly.

I am using bash version 2.05a. What version are you using?



[ Reply to This | # ]
What Version of bash are you using?
Authored by: clh on Jan 01, '02 03:03:48PM

GNU bash, version 2.04.0(1)-release

When you type 'echo $PS1' at the prompt, what does it show?



[ Reply to This | # ]
Missing backslash?
Authored by: clh on Jan 01, '02 03:27:55PM

I tried putting a backslash in front of ${newPWD} in the PS1 definition and it worked. Is that what you use? If so, the backslash got deleted by geeklog in your original post.



[ Reply to This | # ]
What Version of bash are you using?
Authored by: dlandrith on Jan 01, '02 12:16:25PM

With the exception of the export statement that contains the type, this function is exactly (cut and pasted from my profile) what I use and it works perfectly.

I am using bash version 2.05a. What version are you using?



[ Reply to This | # ]