区分本地终端和远程终端

原文连接:Distinguish local and remote terminals

Distinguish local and remote terminals

If you're a heavy user of the command-line, you may have run the wrong command in the wrong terminal window once or twice by accident. This can, of course, have unexpected consequences especially when connected to a production server.

The common utilities like terminal emulators, shells and SSH clients don't really provide anything to prevent these kinds of mistakes. At best, you get a prompt with different username and hostname but telling this apart from your local prompt can be difficult at a glance.

Is there a better way to quickly identify the correct window? In this article we're going to use colors indicate the remote terminal session:

The only terminal emulator I'm aware of that does something similar out of the box is King's Cross. It changes the title bar background color when using SSH or the root user. This article's approach is more configurable and will work with a number of different terminal emulators.

Changing background color

You can usually configure terminal emulator's color scheme to your liking by using a GUI or modifying some configuration file. In addition, many terminal emulators support escape sequences to change colors on the fly. For example, running the following command should change your terminal's background color to a delightful red:

$ printf "\033]11;rgb:ff/00/00\033\\"

If the new color hurts your eyes, reset the background to its original color using:

$ printf "\033]111\033\\"

It's possible that these commands did not work for you. If this is the case, you should:

  • Request this feature from the authors of the terminal emulator or, if possible, contribute the support yourself
  • Investigate if there are other ways of programmatically changing the color scheme in the terminal emulator of your choice
  • Switch to a terminal emulator that supports these escape sequences, such as Alacritty or any VTE-based terminal emulator

Automation

Now that we hopefully have the commands to change the background color, we just need to find a way to run them automatically when using a command like ssh. There are a couple of ways to accomplish this:

  • SSH has an option called LocalCommand which can be used to change the background color after connecting to a server. Unfortunately, there isn't the opposite option that could be used to reset the background color after disconnecting.
  • The background change command can be put in .bashrc file on the server. Similarly, the background reset can be done in .bash_logout. The downside of this approach is that we need to do it for each server.

The best approach, in my opinion, is to create a wrapper for ssh. This is a flexible solution that should work in any situation. Here's the first attempt:

#!/bin/sh
printf "\033]11;rgb:55/11/11\033\\"
ssh "$@" # Pass arguments to the real SSH executable
printf "\033]111\033\\"

This script works in normal circumstances. However, if the script is interrupted (e.g. with Ctrl+C), the background color is not reset. To fix this, let's add a trap to always reset the background color after exit:

#!/bin/sh
trap 'printf "\033]111\033\\"' EXIT INT
printf "\033]11;rgb:55/11/11\033\\"
ssh "$@"

There's still one corner case we need to handle: using ssh with pipelines and redirects. This can be a convenient way of transferring data:

$ ssh server 'mysqldump db_name' > backup-file.sql

In this case, we do not want any escape sequences to mess up our backups or other data. With [ -t 1 ] we can detect whether file descriptor 1, i.e. the standard output, is attached to a terminal. This gives us the final script:

#!/bin/sh
if [ -t 1 ]; then
    trap 'printf "\033]111\033\\"' EXIT INT
    printf "\033]11;rgb:55/11/11\033\\"
fi
ssh "$@"

To use the wrapper, store the script in a file like ~/bin/myssh and run chmod +x ~/bin/myssh to make it executable. Then, run alias ssh=~/bin/myssh to replace ssh command with the wrapper. Now try connecting to a server using the regular ssh server and you should see the background change. Finally, add the alias to your .bashrc (or equivalent file for your shell) to enable the wrapper permanently.

Tweaking

Although we have a working solution, there are still many things we can tweak. First and foremost, you should find a background color that works well with your current color scheme.

Secondly, the same background color is used for all sessions. It may be helpful, for instance, to differentiate development, staging and production servers from each other. We can change the background color based on the name:

# Match substring in arguments like "-p 1234 server1-prod uname -a"
case "$@" in
    *-prod* | *myserver.com* )         printf "\033]11;rgb:55/11/11\033\\" ;;
    *-stg*  | *staging.myserver.com* ) printf "\033]11;rgb:11/55/11\033\\" ;;
    *-dev*  | *localhost* )            printf "\033]11;rgb:11/11/55\033\\" ;;
    * )                                printf "\033]11;rgb:55/11/55\033\\" ;;
esac

If you have many servers, consider adding them in your SSH configuration with a consistent naming like server1-dev and server2-prod.

The text may be hard to read if only the background color is changed. Conveniently, there are additional escape sequences that can be used to change the whole color scheme on the fly. For example, to use the excellent Solarized Light color scheme, run the following commands:

printf "\033]10;rgb:65/7b/83\033\\"   # set foreground color
printf "\033]11;rgb:fd/f6/e3\033\\"   # set background color
printf "\033]12;rgb:58/6e/75\033\\"   # set text cursor color
printf "\033]13;rgb:58/6e/75\033\\"   # set mouse foreground color
printf "\033]14;rgb:93/a1/a1\033\\"   # set mouse background color
printf "\033]4;0;rgb:ee/e8/d5\033\\"  # set black
printf "\033]4;1;rgb:dc/32/2f\033\\"  # set red
printf "\033]4;2;rgb:85/99/00\033\\"  # set green
printf "\033]4;3;rgb:b5/89/00\033\\"  # set yellow
printf "\033]4;4;rgb:26/8b/d2\033\\"  # set blue
printf "\033]4;5;rgb:d3/36/82\033\\"  # set magenta
printf "\033]4;6;rgb:2a/a1/98\033\\"  # set cyan
printf "\033]4;7;rgb:07/36/42\033\\"  # set white
printf "\033]4;9;rgb:cb/4b/16\033\\"  # set bright black
printf "\033]4;8;rgb:fd/f6/e3\033\\"  # set bright red
printf "\033]4;10;rgb:93/a1/a1\033\\" # set bright green
printf "\033]4;11;rgb:83/94/96\033\\" # set bright yellow
printf "\033]4;12;rgb:65/7b/83\033\\" # set bright blue
printf "\033]4;13;rgb:6c/71/c4\033\\" # set bright magenta
printf "\033]4;14;rgb:58/6e/75\033\\" # set bright cyan
printf "\033]4;15;rgb:00/2b/36\033\\" # set bright white

Run the following to restore the original color scheme:

printf "\033]110\033\\" # reset foreground color
printf "\033]111\033\\" # reset background color
printf "\033]112\033\\" # reset text cursor color
printf "\033]113\033\\" # reset mouse foreground color
printf "\033]114\033\\" # reset mouse background color
printf "\033]104\033\\" # reset other colors

Changing and managing color schemes using raw escape sequences may become unwieldy. Instead, you can use utilities like theme.sh, pywal and xtermcontrol to make things easier.

Understanding escape sequences

How do these escape sequences work? Terminals basically display text but with special sequences we can send commands to do more interesting things, such as controlling output formatting or building complete TUIs. Let's break down the familiar escape sequence "\033]11;rgb:ff/00/00\033\\":

  • \033] are two characters that mark the start of Operating System Command (OSC). Specifically, \033 is the number 27 in octal, i.e. ESC or escape character in ASCII, and ] is just the right square bracket it looks like. \033 is a special syntax supported by printf command.
  • 11 is the numeric identifier for command that changes the background color of the terminal.
  • ; separates arguments.
  • rgb:ff/00/00 is the first and only argument. The format is based on XParseColor function from XLib. More familiar #ff0000 syntax is also supported but its use is not encouraged.
  • \033\\ is ESC followed by the backslash \. This two character sequence is known as the string terminator (ST) and here it marks the end of OSC. \\ is the way of escaping the backslash character in a double-quoted string.

With this in mind, the other escape sequences presented in this article should not look too cryptic anymore. These escape sequences among others are documented thoroughly in XTerm Control Sequences.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值