Bash prompt to change color when I am logged into a server

Is there a way to make the bash prompt dynamic, so that it changes color when logged into a server?

So I want the like the color to be green when on my system and change to red when connected to servers. I have huge number of servers I don't want to put a different .bashrc on all those.


The remote prompt is set by the remote ~/.bashrc. So you still need to copy it to the remote server. However, you can use a single ~/.bashrc for all hosts, and set the prompt color based on hostname:

[ "$PS1" ] || return 0                           # continue only when interactive
case $(hostname -s) in
laptop*)
    prompt_color='\033[48;5;16m\033[38;5;46m'    # green(46) on black(16)
    ;;
server*)
    prompt_color='\033[48;5;16m\033[38;5;196m'   # red(196) on black(16)
    ;;
esac
ORIG_PS1=$PS1                                    # in case needed
PS1='<\['${prompt_color}'\]\h\[\033[m\]:\w>\$ '
unset prompt_color

Notes:

  • Don't set PS1 if it's not already set (i.e., if the shell is not interactive). Testing if PS1 is non-empty is a very common way to decide if the shell is interactive, and you don't want to confuse programs that do that. (Arguably a more accurate test is checking if $- contains i.)

  • If you want this code to run when logging into a remote server, you should have one of the profile files always source ~/.bashrc. But I assume you know that.

  • In PS1, the escape codes must be enclosed in \[...\].

  • \[033[m resets foreground and background to default. So here, :\w appear in terminal foreground/background.

  • \[033[48;5;XXXm\033[38;5;YYYm sets the background/foreground to XXX/YYY.

  • For a script that dumps the available colors, try colortest.

  • To check what the prompt would look like:

    echo -e "<\033[48;5;16m\033[38;5;196mhost\033[m:dir>$ "
    

If you don't want to (can't) make the remotes have a separate PS1, then I'd say "no", it would be at least awfully difficult. Consider that on an SSH connection the local side has no real idea of what is a shell prompt and what is something else, and so setting colors for the prompt really has to come from the remote. You could set colors before starting the session, but they'd be effective for all output, that is until an ls or an editor sets colors of it's own.

Of course you could come up with some wrapper for the session to detect everything looking like a prompt and to colorize it, but it would easily lead to false positives (color on every line with a $?) and be awfully complicated compared to just dropping a single line to your .profile or .bashrc on each machine.

With a number of machines, it might be useful in any case to search for solutions to synchronize configuration changes on all of them. Be it some tool made for it, or just a script, or just running a loop to copy a (set of) config file(s) on them all.


I am using a wrapper script with sshpass that will first upload a temporary profile and then ssh using this profile (and delete the temp file).

The two main things of the script are these:
scp ~/.bash_remote "${USER}"@"${IP}":/tmp/.bash_tmp 1>/dev/null
ssh -t "${USER}"@"${IP}" "bash --rcfile /tmp/.bash_tmp; rm /tmp/.bash_tmp"

Using this you can easily define the colors of the remote sessions.

I know this doesn't directly answer your question, but it could be used to solve it.


You might be interested in context-color, which I've put together for that exact purpose: https://github.com/ramnes/context-color

It's a simple script that, when executed, outputs a color based on a command output's hash. With it installed somewhere in your $PATH, you could do something like this in your .bashrc:

export PS1="$(context-color -p)$PS1\[\e[0m\]"

(where --prompt/-p is the switch so that the color is escaped for prompts, and \[\e[0m\] the escape sequence to reset color)

By default, the command used to generate the hash is whoami; hostname. If you just want the color to change according to the hostname, you can change the $CONTEXT variable environment (export CONTEXT="hostname") or simply use the --context/-c option (context-color -c "hostname").

See below for an example:

demo