Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I use tcsh. I'd like to have my prompt formatting (coloring/highlighting) change based on the directory I'm in, or other critical aspects of my environment.

I'm not enough of a shell hacker to know how to do this.

Ownership of Current Directory

If I'm in one of "my" directories (i.e., I am owner of the current working directory), then it should have normal appearance. But if I'm in someone else's directory (I do a lot of support and cd to others' working areas), then I want the prompt to look clearly different.

This is to remind me to not type impolite commands in others' directories. (think make clobber or p4 sync, etc.)

Critical Environment Variable Setting

Another important piece of information for my environment is whether a certain environment variable is set, call it SWDEV. If SWDEV is not set, then my scripts and flows come from their default location. But if this variable is set, then it's taken as a new root location for my scripts and flows, with behaviors changing according to the scripts at that location.

It's important to be reminded of the setting of this variable, lest I expect "normal" behavior but instead absentmindedly run code from the new location.

share|improve this question

3 Answers 3

Well, if an external script is an acceptable solution, you could do something like this:

#!/usr/bin/env perl 
use Cwd;
my $cwd=getcwd();
$cwd =~ /$ENV{HOME}/ ? 
             print "$cwd % " : 
             print "%{\033[1;31m%}CAREFUL\\\!%{\033[0m%} $cwd % ";

Save that somewhere in your $PATH as make_prompt.pl and make it executable. And then, in your ~/.tcshrc :

alias precmd 'set prompt="`make_prompt.pl`"'

This will result in:

                     enter image description here

You can also add more conditions to change the prompt in specific ways in different directories:

#!/usr/bin/env perl 
use Cwd;
my $cwd=getcwd();

## Here are some colors to choose from
my $red="%{\033[1;31m%}";
my $green="%{\033[0;32m%}";
my $yellow="%{\033[1;33m%}";
my $blue="%{\033[1;34m%}";
my $magenta="%{\033[1;35m%}";
my $cyan="%{\033[1;36m%}";
my $white="%{\033[0;37m%}";
## This resets the color, you need it after each color command
my $end="%{\033[0m%}";


## If you are in $HOME or one of its sub dirs, print a green prompt
if($cwd =~ /$ENV{HOME}/){
   print "$green$cwd$end % ";
}
## If you are in /usr or one of its sub dirs, print a red prompt
elsif($cwd=~ /\/usr/){
   print "$red$cwd$end % ";
}
## If you are in /etc or one of its sub dirs, print a blue prompt
elsif($cwd=~/\/etc/){
    print "$blue$cwd$end % ";
}
## If you're in /root. As you can see, colors can be combined
elsif($cwd=~/\/root/){
    print $red . "OY\\! You're not allowed in here\\!" . 
          $end . $magenta . " $cwd$end % ";

}
## For wherever else, just print a plain prompt
else {
    print "$cwd % ";
}
share|improve this answer
    
@illuminÉ thanks, it was a typo, it should work now. Note the backticks around the perl script's name (theyŕe not very visible). –  terdon Feb 6 at 18:10
    
@illuminÉ see updated answer. I added a version of the script with some more options. You can add as many elsif blocks as you wish. –  terdon Feb 8 at 14:19
    
Your solutions were inspiring and enabling. That was fun! Shell prompts are always about detail. Thank you for the contribution! –  Amphiteót Feb 11 at 3:40
    
The real trick here is the precmd. You can do anything you want in a shell function, then use the function as the precmd. You don't need an external script. As long as the script takes to run, your prompt will be delayed by that amount of time. Handling everything natively within the shell will reduce this latency. –  bahamat Feb 11 at 22:23
    
@bahamat absolutely, yes. I just don't know [t]csh syntax and since the OP specified that an external script is acceptable I thought I'd suggest one. –  terdon Feb 12 at 4:48
up vote 2 down vote accepted
+100

I didn't figure out how to do this natively in shell (tcsh), but I did solve the problem using a Perl script.

With a Perl script, you can have logic as sophisticated as you want to check whether you own the $cwd, what environment variables are set, etc. Then, have the script print the prompt string you'd like.

tcsh has a special precmd alias that is executed each time before the prompt is printed. So, having a Perl script "formatPrompt.pl"

#!/home/utils/perl-5.8.8/bin/perl

use strict;
use warnings;

use Cwd;
# "SWDEV" is an env var special to our environment. Want to be reminded in the prompt of its setting.
use Env qw(SWDEV prompt);

my $prompt = '%U{%m}%~%u> ';
my $prefix = '';

if (defined $SWDEV) {
    # set a prompt prefix if special env var is set. use "Boldface" highlighting.
    $prefix = "%Bspecial env var SWDEV=$SWDEV%b\\n";
}
if (! -o getcwd) {
    # change the highlighting of the prompt if not your dir.
    $prompt = '%U{%m}-->%~<--%u> ';
}
$prompt = $prefix . $prompt;
print $prompt;

exit 0;

and an alias defined such

% alias precmd
set prompt="`perl /home/source/perl/formatPrompt.pl`"

can produce

{o-xterm-62}~> setenv SWDEV "/some/special/env/var/value"
special env var SWDEV=/some/special/env/var/value
{o-xterm-62}~> cd /usr
special env var SWDEV=/some/special/env/var/value
{o-xterm-62}-->/usr<--> unsetenv SWDEV
{o-xterm-62}-->/usr<--> cd ~
{o-xterm-62}~>

(Note that if SWDEV is set, its value is printed, and that the cwd is surrounded by -->cwd<-- if the dir is not owned by the user. Try other prompt highlighting such as %S%~%s, also.)

enter image description here

share|improve this answer
    
Thanks for your attention in helping develop answers. –  user7810 Feb 11 at 2:04
    
There is another feature of the script that I neglected to describe. Besides changing the prompt based on whether I own cwd, it also changes the prompt based on the setting of a particular environment variable that is significant in our environment, "SWDEV" in my example. If "SWDEV" is set, "something different" happens that depends on the var's value. That's why I print this in the prompt as a reminder. In trying to explain, I can't think of a good example of this in a generic Unix environment -- it's just that this var is significant for us. –  user7810 Feb 11 at 2:11
    
You're welcome! Now I understand what this was about concretely. Thank you for taking the time to explain that and update the script! That was really interesting and fun! Cheers!:) –  Amphiteót Feb 15 at 1:14

For fun I provide another prototype, based on what I've seen the others do here, using simple if statements; make_prompt:

#!/bin/tcsh

set     red="%{\033[1;31m%}"
set   green="%{\033[1;32m%}"
set  yellow="%{\033[1;33m%}"
set    blue="%{\033[1;34m%}"
set magenta="%{\033[1;35m%}"
set    cyan="%{\033[1;36m%}"
set   white="%{\033[0;37m%}"
set     end="%{\033[0m%}" 

if ("$dirstack[1]" == "/") then
  echo " ${blue}r${magenta}o${cyan}o${green}t${end} "
else if ("$dirstack[1]" =~ "/home/thisguy*") then
  echo " ${yellow}Watch this guy out\\!${end} "
else if ("$dirstack[1]" =~ "/hom*") then
  echo " ${red}Be mindful of the home dir\\!${end} "
else if ("$dirstack[1]" =~ "/usr*") then
  echo " ${magenta}You're in /usr now\\!${end} "
else if ("$dirstack[1]" =~ "/etc*") then
  echo " ${green}-=etc=-${end} "
endif

With the bit that goes in .tcshrc, opting to use rprompt instead of prompt to automatically align the information to the right:

alias precmd 'set rprompt="`if "$?" == 0 echo "\(ok\)"``if "$?" == 1  echo "\(err\)"``if ("$?" != 0 && "$?" != 1) echo "\($?\)"``make_prompt`"'

Also added is a simple indication of the exit status of the last command (ok = 0, err = 1, $? for anything else).

Limitation is that a specific order is required (from the specific to the general) when making custom messages in the script for directories that are objects within others i.e. /home/thisguy vs. /home here.

enter image description here

share|improve this answer
    
I can't colorize the exit status because I can't introduce the color sequences in alias precmd, however hard I try. Why not do it in the script? I don't know if it's me (a beginner) but tcsh won't go through a second if/endif block in that context of precmd executing the script - only the first if/endif block gets processed and the other is just ignored?! Also, the space after the $(end) in the script is required to stop colors from leaking. Indeed if the color stopping is the last item with no space, it is ignored (%{string%} cannot be the last in prompt). But overall it's not bad. Cheers! –  Amphiteót Feb 9 at 18:14
    
The dirstack array was used to make it more tcsh-ish. I had intended for the script to not print its stuff every time; I wanted to push the last dir used with pushd to second position in stack then compare it, and not print if it's same, but the precmd framework has impacts... so it's beyond me. Finally I found exploring this and this was insightful. Also this wonderfully amazing document. –  Amphiteót Feb 9 at 18:32

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.