10.17.2008

Prompt and Circumstance

On most GNU/Linux installs, I tend to setup my BASH prompt as follows:

jstorm[0]@absinthe:~$
Most of this is purely cosmetic, allowing me to visually parse the information a little more easily, but the "[0]" is relatively special. The number next to the username is actually the number of jobs I have running at any given point in time. I tend to run quite a few concurrent terminals, and with no visual aid to help me determine which of these have background tasks, it becomes something of a pain trying to track down that last vim instance, hoping I didn't up and close the whole BASH session.

Oh, and in case you're wondering, I typically set up my prompt with this mess:

export PS1='\[\e[3;31m\]\u\[\e[3;37m\][`jobs | wc -l`]\[\e[0;0m\]@\[\e[0;31m\]\h\[\e[0;0m\]:\[\e[0;0m\]\W\[\e[0;0m\]\[\e[3;31m\]\$\[\e[0m\] '

This evening, having finally gotten around to bringing over my usual .vimrc and .profile to my lovely, little MacBook, I soon discovered that there was treachery afoot...

jstorm[ 0]@absinthe:~$

"What in the hell is that?" I fumed. Suddenly, a tab appears in front of the output of wc, and I'm supposed to believe it got there all by itself?! "Hah! I'll fix its wagon," said I, triumphantly.

I then discovered that, while the version of wc I'm used to removes the first indent when producing only a single value--a word count, for instance--the version used on OS X retains the indent, no matter what. Thus, I endeavored to remove the whitespace using PERL:

jstorm[0]@absinthe:~$ jobs | wc -l | perl -e "foreach (<>) { s/\s+//; print $_ }"
0


Tada! Goodbye, whitespace! Now, all I had to do was make it work within the context of my .profile--which brings me to my next issue. Because the shell will try to interpret the $_, I must use single quotes around the PERL code when using it as part of PS1's value. The trouble with this is that the PS1 environment variable already has single quotes around the value. This means that the shell will find a string literal and some uninterpretable junk, followed by another string literal. Observe:

'commands 'some stuff' more commands'

Where does the nested string literal begin and end? The trouble is that the shell will pair up the first two single quotes rather than parse the two middle quotes as their own pair. Hmm... what to do. Well, to my eyes, what made the most sense was to pack up the PERL command in its own little shell script, then call that. Here is the result:

jstorm[0]@absinthe:~$ cat Documents/scripts/rmws.sh
#!/bin/bash

cat | perl -e "foreach (<>) { s/\s+//; print $_ }"


Then, I adjusted PS1 in my .profile:

export PS1='\[\e[3;31m\]\u\[\e[3;37m\][`jobs | wc -l | ~/Documents/scripts/rmws.sh`]\[\e[0;0m\]@\[\e[0;31m\]\h\[\e[0;0m\]:\[\e[0;0m\]\W\[\e[0;0m\]\[\e[3;31m\]\$\[\e[0m\] '

And voila! Since all I tend to do is deal in kludges, I don't tend to mind the relative sloppiness. After all, it works--and well, at that. Why should I care?

And the proof:

jstorm[5]@absinthe:~$ jobs
[1] Stopped vim
[2] Stopped vim
[3] Stopped vim
[4]- Stopped vim
[5]+ Stopped vim
jstorm[5]@absinthe:~$ kill -KILL %5
[5]+ Killed vim
jstorm[5]@absinthe:~$
jstorm[4]@absinthe:~$


QED

And there you have it: close enough for government work.

No comments:

Post a Comment