shell 通过SSH会话检测iTerm2终端?

33qvvth1  于 2023-05-01  发布在  Shell
关注(0)|答案(2)|浏览(96)

我想发送一些专有转义到iTerm 2(覆盖当前颜色配置文件中的背景颜色),如果我的会话是通过SSH运行。
为了在使用其他终端时不搞砸终端或打印垃圾,我想检测终端是否实际上是iTerm 2。根据在网络上找到的信息[1],可以检查ITERM_SESSION_ID环境变量。但是,此变量是为本地会话设置的,而不是在SSHing到另一台机器时设置的。
这个想法是把类似下面的东西放在我的。zshrc(我用的是相同的。所有机器上的zshrc):

if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then

    # we are running over SSH...

    if [ -n "$ITERM_SESSION_ID" ]; then
        # change terminal bg color:
        # (can do more advanced stuff to better identify the remote machine)

        echo -e '\e]1337;SetColors=bg=525\a'
    fi
fi

但是,由于变量ITERM_SESSION_ID在SSHing时被重置,因此它不会工作。
我需要在ssh客户端/服务器上分别设置SendEnv/AcceptEnv,但这似乎是一个坏主意。
有没有其他方法可以获得类似的结果(只有在支持的情况下才使用专有转义?))?
或者我应该只是不关心那些不支持?
1:https://groups.google.com/g/iterm2-discuss/c/MpOWDIn6QTs?pli=1

s5a0g9ez

s5a0g9ez1#

VT 100类终端可以设置为在接收到ENQ字符(Ctrl-E、ASCII 005)时发送标识字符串。这几乎包括您可能使用的任何现代终端-PuTTY、XTerm、iTerm 2等等。这个功能有时被称为“应答”。
在iTerm 2的情况下,应答功能简要记录为here。您可以在“终端”选项卡上配置应答字符串:

iTerm 2的默认应答是一个空字符串,因此您必须在配置文件中更改它。这样做的好处是,您可以在配置文件中放置任何您喜欢的内容,并可能针对不同的目的使用不同的应答。
https://unix.stackexchange.com/上的This post更详细地讨论了该功能,包括您可能期望从其他终端获得的内容以及如何在脚本中可靠地读取字符串。简单地说,其中一个建议是运行这个命令:

stty raw min 0 time 5; echo -ne '\005' && read -s; stty cooked; echo -n "${REPLY}"

将发送ENQ字符并等待客户端响应一小段时间。客户端不能发送任何内容,或者它的响应不能以换行符终止。

huus2vyu

huus2vyu2#

this discussion on the iterm2-discuss mailing list
我想我知道如何判断你的终端是不是iTerm 2了。它需要在不同平台上广泛部署之前进行测试。
问题一直是环境变量不被传递,几乎所有的终端都不支持转义序列来报告版本号。Commit cc 8436 b增加了对新转义序列的支持,该序列报告应被所有其他终端忽略的终端名称和版本号。诀窍是你不能只要求版本然后读回来,因为如果终端不支持新的序列,这将无限期地挂起。相反,您发送自定义序列,然后发送每个终端都支持的标准“设备状态报告”。然后你读回一个响应,如果它是DSR响应,你就退出,知道它不是iTerm 2。否则,请阅读两个答案。
Commit 95 c439 f44 a77 e2419 c73 e2 a44 e7 f0 b423 ed 37368添加了一个shell脚本,用于测试当前终端是否为iTerm 2,并可以选择检查其版本号是否大于或等于您指定的版本号。
它将只在支持这个新转义序列的iTerm 2版本上工作,从明天的夜间构建(2.9.20160304)。
tl;dr:您可以使用以下脚本判断终端是否为iTerm 2:https://raw.githubusercontent.com/gnachman/iTerm2/master/tests/isiterm2.sh

#!/usr/bin/env bash
# Make sure stdin and stdout are a tty.
if [ ! -t 0 ] ; then
  exit 1
fi
if [ ! -t 1 ] ; then
  exit 1
fi

# Read some bytes from stdin. Pass the number of bytes to read as the first argument.
function read_bytes()
{
  numbytes=$1
  dd bs=1 count=$numbytes 2>/dev/null
}

function read_dsr() {
  # Reading response to DSR.
  dsr=""
  spam=$(read_bytes 2)
  byte=$(read_bytes 1)
  while [ "${byte}" != "n" ]; do
    dsr=${dsr}${byte}
    byte=$(read_bytes 1)
  done
  echo ${dsr}
}

# Extract the terminal name from DSR 1337
function terminal {
  echo -n "$1" | sed -e 's/ .*//'
}

# Extract the version number from DSR 1337
function version {
  echo -n "$1" | sed -e 's/.* //'
}

trap clean_up EXIT
_STTY=$(stty -g)      ## Save current terminal setup

function clean_up() {
  stty "$_STTY"            ## Restore terminal settings
}

# Prepare to silently read any (>=0) characters with no timeout.
stty -echo -icanon raw min 0 time 0

# Consume all pending input.
while read none; do :; done

# Reset the TTY, so it behaves as expected for the rest of the it2check script.
clean_up 

# Enter raw mode and turn off echo so the terminal and I can chat quietly.
stty -echo -icanon raw

# Support for the extension first appears in this version of iTerm2:
MIN_VERSION=2.9.20160304
if [ $# -eq 1 ]; then
  MIN_VERSION=$1
fi

# Send iTerm2-proprietary code. Other terminals ought to ignore it (but are
# free to use it respectfully).  The response won't start with a 0 so we can
# distinguish it from the response to DSR 5. It should contain the terminal's
# name followed by a space followed by its version number and be terminated
# with an n.
echo -en '\e[1337n'

# Report device status. Responds with esc [ 0 n. All terminals support this. We
# do this because if the terminal will not respond to iTerm2's custom escape
# sequence, we can still read from stdin without blocking indefinitely.
echo -en '\e[5n'

version_string=$(read_dsr)
if [ -n "${version_string}" -a "${version_string}" != "0" -a "${version_string}" != "3" ]; then
  # Already read DSR 1337. Read DSR 5 and throw it away.
  dsr=$(read_dsr)
else
  # Terminal didn't respond to the DSR 1337. The response we read is from DSR 5.
  version_string=""
fi

# Extract the terminal name and version number from the response.
version=$(version "${version_string}")
term=$(terminal "${version_string}")

# Check if they match what we're looking for. This becomes the return code of the script.
test "$term" = ITERM2 -a \( "$version" \> "$MIN_VERSION" -o "$version" = "$MIN_VERSION" \)

此处提供脚本:https://iterm2.com/utilities/it2check
注意:在上面的脚本中,我用-e '\e'替换了raw escape char。

相关问题