5

I've had problems with people logging into some servers via ssh and forgetting that a specific terminal is no longer local. Today someone tried to shutdown their laptop with sudo shutdown -h now, and accidentally took down a server.

I'd like to change the colour of bash's PS1 on these servers when logged in via ssh. I control these servers via a debian package that I push to them.

What's the best way to push a site-wide PS1 default?


The obvious answer is to create a file /etc/profile.d/sshcolours with this content to make the user@host purple:

if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ] ; then PS1='\[\033[01;35m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' fi 

bash will read that via /etc/profile (which sources /etc/profile.d/*). However, it will later read ~/.bashrc which will probably override PS1 based on $TERM as defined in /etc/skel/.bashrc.

Is there some way I can source my site-wide file after ~/.bashrc without touching ~/.bashrc and without forcing my team to adopt a client-side change?


Here are a couple of bad ideas:

  1. After setting $PS1, ~/.bashrc conditionally sources /usr/share/bash-completion/completions/*, so I could put my file there. But some testing showed me that the condition isn't met, or /usr/share/bash-completion/bash_completion reverts the environment.

  2. In postinst I could append a line to source my file to each user's ~/.bashrc. This feels both illegal and buggy:

for h in /home/*; do if [ ! grep -q profile_amendments "$h/.bashrc" ] ; then echo ". /etc/profile_amendments" >> "$h/.bashrc" fi done 
3
  • 1
    Have you considered limiting users powers instead? I don't think purple text is going to help much if they already don't check the hostname. What if their local PS1 is purple also? Commented May 10, 2024 at 11:31
  • My team should have the power to shutdown or reboot the servers, so tweaking /etc/sudoers isn't going to help. It's hard to choose a colour that will work for everyone without changing the client-side procedure. Commented May 10, 2024 at 11:35
  • Possibly dumb idea: replace /sbin/shutdown with a script that prints something like WARNING, $HOSTNAME WILL SHUT DOWN IN 30 SECONDS, sleep a bit and then run the actual systemctl command. Commented May 10, 2024 at 11:38

3 Answers 3

3

If your users set their preferred $PS1 in their ~/.bashrc but do not set the $PROMPT_COMMAND variable, you could add:

if [[ -n $SSH_CLIENT$SSH_TTY ]]; then PROMPT_COMMAND=' if [[ $PS1 != *SSH* ]]; then PS1="\[\e[35m\][SSH]\[\e[m\] $PS1" unset -v PROMPT_COMMAND fi ' fi 

To /etc/bash.bashrc (or equivalent on your system) for a purple [SSH] to be prepended to $PS1 just before the first prompt.

In any case /etc/profile is the session configuration file, not shell customisation file.

In bash 5.1 or newer, $PROMPT_COMMAND can now be an array (reminiscent to zsh's $precmd_functions array), so you could append to that array and unset only that array element in the code there. As usual, it's more cumbersome there where arrays are sparse arrays and getting the index of the last element is rather awkward:

if [[ -n $SSH_CLIENT$SSH_TTY ]]; then PROMPT_COMMAND+=(' if [[ -v ssh_check_index ]]; then PS1="\[\e[35m\][SSH]\[\e[m\] $PS1" unset -v "PROMPT_COMMAND[ssh_check_index]" ssh_check_index fi ') ssh_check_index=( "${!PROMPT_COMMAND[@]}" ) ssh_check_index=${ssh_check_index[@]: -1} fi 

As you suggested, as long as the rest of /etc/bash.bashrc (before or after that code) and users' ~/.bashrc also use PROMPT_COMMAND+=('code') to add code to $PROMPT_COMMAND instead of replacing it entirely, that will avoid those codes to be removed as the unset -v PROMPT_COMMAND from the previous approach would.

Rather than changing the prompt, some other approach could be to change the terminal default background and foreground colours (assuming users use xterm-like terminal emulators) like:

printf '\e]11;#bb88ff\e\\\e]10;#000000\e\\' 

For black on light purple or

printf '\e]11;#440055\e\\\e]10;#dddddd\e\\' 

For white on dark purple if users tend to prefer dark backgrounds.

You could also add \e]12;#ff0000\e\\ to make the cursor bright red, or change the font, etc.

4
  • I think this is a good solution. It overcomes the problems with overriding things that are normally set by the user. Would it make more sense to PROPT_COMMAND+=(...)? This would avoid overwriting things that could be set earlier, and lets later scripts append more content. Commented May 13, 2024 at 17:19
  • Also, why did you set PS1 from PROMPT_COMMAND instead of running PROMPT_COMMAND+=("printf ...")? Commented May 13, 2024 at 17:38
  • @Stewart, note that only bash 5.1 or newer support PROMPT_COMMAND as an array. I've added an approach using that. Printing stuff before the prompt on the same line like with your PROMPT_COMMAND+=('printf...') generally messes up the line editor which then has the wrong idea of where the cursor is. That will usually manifest when you reach the right end of the script. Using PS1 and tell the line editor with those \[...\] which part of the prompt doesn't move the cursor avoids the issue. Commented May 13, 2024 at 20:47
  • @Stewart, sorry meant the right end of the screen (when the cursor wraps to the beginning of the next line), not script. Commented May 14, 2024 at 15:53
3

You've explained that your users need to be able to perform privileged operations on the remote servers. I don't see a way to override their prompts, screen colours, etc. without their cooperation. You could ask them to add a . /etc/profile_amendments to the end of their .bashrc and .bash_profile files, for example, but I know of no way to enforce this.

The remainder doesn't directly answer your question but is more thinking about alternative solutions. Maybe modifying the sudo configuration could help. For example, using visudo /etc/sudoers.d/lecture to create a file like this could help:

# https://unix.stackexchange.com/questions/776200/setting-ps1-with-site-wide-configuration # # visudo /etc/sudoers.d/lecture # vi /usr/local/etc/sudo-lecture.txt ######################################################################## # Defaults lecture="always" Defaults lecture_file="/usr/local/etc/sudo-lecture.txt" Defaults timestamp_timeout=3 

You'd then supplement it with the text contents of /usr/local/etc/sudo-lecture.txt

## ATTENTION ## ## ## This is server FROGGIT ## 

References

1
  • 1
    Nice lateral answer that addresses the core problem (instead of just the question asked). I'd still like colours, but I might also do this. Commented May 10, 2024 at 12:12
0

If you're willing to force clients to run their shell in a tmux session, you could spawn a tmux session at the end of /etc/profile, before ~/.bashrc is sourced, colorizing the bottom bar, so that any change to the prompt done by the users' ~/.bashrc will not override the visual cue.

I.e., something like:

if [ ! -z "$TERM" ] && [ -z "$TMUX" ]; then tmux exit "$?" fi 

At the end of /etc/profile; by default, this will spawn a tmux session with a green bottom bar.

The guards are in place to avoid spawning tmux instances if /etc/profile is not being sourced from a Bash instance running in a terminal, and to avoid recursively spawning tmux instances.

exit "$?" will exit /etc/profile returning tmux's exit code.

example

In this example, the prompt is set by ~/.zshrc, which is a modified version of Grml's ~/.zshrc, but the bottom bar is set by tmux in /etc/zprofile.

The modifications done by ~/.zshrc still apply, and it doesn't matter how I change ~/.zshrc: the bottom bar will stay. The same principle will apply to ~/.bashrc / /etc/profile.

As an addedd bonus, plagiarizing myself on Ask Ubuntu (read the answer there for details and limits to this method), you could expand this to have the bottom bar be automatically set to a pseudo-machine-specific color, to simplify deployment of the modification on different servers in case you wish to have the bottom bar's color pseudo-uniquely identify each server:

if [ ! -z "$TERM" ] && [ -z "$TMUX" ]; then tmux_default_session_name=Default tmux_bg_color=# tmux_fg_color=#000000 tmux_bg_color_brightness=0 for c in $(cut -c27- /etc/machine-id | fold -w2); do tmux_bg_color="${tmux_bg_color}${c}" tmux_bg_color_brightness=$((tmux_bg_color_brightness + 16#${c})) done tmux_bg_color_brightness=$((tmux_bg_color_brightness / 3)) [ "$tmux_bg_color_brightness" -lt 128 ] && tmux_fg_color=#ffffff tmux new-session -d -s "$tmux_default_session_name" tmux set-option -t "$tmux_default_session_name" status-style "bg=${tmux_bg_color}" tmux set-option -at "$tmux_default_session_name" status-style "fg=${tmux_fg_color}" tmux set-option -at "$tmux_default_session_name" terminal-features ',*:RGB' tmux attach -t "$tmux_default_session_name" exit "$?" fi 
2
  • Not willing for force people to use tmux, but I bet your answer could be useful to someone else. Commented May 16, 2024 at 14:14
  • @Stewart It certainly has been useful to me, I used to do the same as your users sometimes (and, in general, I'd argue tmux might only increase productiveness, if one's willing to learn a few keystrokes). But I get tmux might not be for everyone / for every environment. Commented May 16, 2024 at 14:43

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.