最近公司正版整顿,不让使用 SecureCRT 了(主要是 Windows 转过来了),乘机推广一波 iTerm2,但基本只有些入门教程,稍微深入点的没有,所以自己总结了下
全文: https://iyaozhen.com/iterm2-tips.html 可能阅读体验更好
摘录:
iTerm2 的优点这里不做赘述了,第一次使用的话可以先看看官网的介绍:features 、Highlights for New Users 。本文主要是结合实际使用场景,介绍一些进阶使用技巧(基本的 Oh My Zsh 、rzsz 等配置就不重复说明了)。
现在很多公司登录服务器都需要先登录到一个跳板机然后再登录到目标机器,每次输入密码(一般还是动态的)很麻烦。一般的教程推荐使用 expext 解决这个问题,这里介绍一个更简单、直接的办法。
首先,要先解决登录到跳板机的连接复用问题,这个输入 ssh 本身的范畴,一般教程都是说在 ~/.ssh/config 增加下面的配置:
host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
但这样有个问题,iTerm2 第一次登录的 tab 关闭后,就失效了,再登录就又要密码了。其实再增加一个配置即可。
ControlPersist yes
ServerAliveInterval 60
之前的设置只是实现了连接复用,但 tab 关闭 ssh 进程结束后,连接也被销毁了,ControlPersist 项的意思是进程结束后连接还保持,再有相同的( ControlPath 配置)连接,还能继续使用此连接。
再者,每次输入 ssh xxx 很麻烦(而且跳板机登录后还得输入 ssh xxx ),当然你可以配置 alias+expext 但也不是太方便,特别是 Windows 转过来的。对此,iTerm2 本身也提供了很强大的 Profiles 功能,能一键登录目标机器(还可以设置快捷键)。
有些自己的常用机器,还可以复制一下这份基础的 relay 配置。
再加一行( Send text at start 处)。
还可以把机器打个标签,然后页面上就能分组,方便选择。
还有一个,有时候会发现,有些机器一会儿没操作就会被断开 ssh,一方面可以设置 ServerAliveInterval,但作用不大,因为实际连接服务器的是 relay 跳板机。iTerm2 其实没有可以显式设置这个功能的地方,有些同学可能找到个这个配置:
可能错误使用的比较多,iTerm2 还特意提示了,开启这个功能不能 session 保持。那到底有没有办法呢,还是有的。其实这个特性是为了安全,是 TMOUT 环境变量控制的,export 设置一个比较大的值(比如 12h,保证第二天来了不断就行)。这个可以设置在自己常用机器的环境变量里,或者定义一个 Snippet 方便使用(后面还有介绍)。
到此基本上解决了如何便捷登录机器的问题。但之前用 SecureCRT 的同学可能有个地方不太习惯,iTerm2 的 Duplicate Tab 只能复制当前的 profile,比如我先快捷键打开 relay profile,然后输入 ssh 到一台机器,此时复制的 tab,只到 relay 跳板机,还得翻一下之前的 ssh 命令。
不过直接打开的就是之前配置的 test02 这种 profile,复制 tab 的时候就能直接到当前机器登录状态。但一般管理的机器非常多,不可能都配置到 profile,还是有点不方便。不过这个也能解决,下面 script 自定义脚本章节有介绍。
iTerm2 还有个非常强大的功能,就是支持自定义脚本,而且新版的脚本可以用 Python 写,只要想象力够丰富,可以实现很多功能。动手前可以先多看几遍官网的文档说明:Scripting Fundamentals 。
先介绍一些基本概念,上下文按层级划分:app 、window 、tab 、session,如下图所示:
我们做一些操作的时候需要明白操作的上下文对象,那么一个对象具体可以做什么呢,需要看具体文档: https://iterm2.com/python-api/。可以按照官方示例做一遍,官网也有很多例子可以参考。
下面我们尝试用 script 来实现增强版的 Duplicate Tab 的功能,能复制当前已登录的服务器。模拟我们手工操作的过程,可以把步骤分为 3 部分:
一开始我看到 tab 的名称都能显示当前 host,但查了一番资料未果。中间查阅文档发现 iTerm2 内置了很多变量,其中有 hostname,但试了下只能获取到 Mac 电脑的 hostname 。后来又想我在服务器上执行 hostname 命令,然后怎么把这个结果传递给 iTerm2 。
一通翻文档,发现了 iTerm2 有个特殊的 Escape Codes 功能,简单来说就输出包含一些特殊字符的时候,屏幕上不会显示,但 iTerm2 会捕获这种逃逸字符,然后实现一些特殊功能。比如强大的 Shell Integration 就是基于此实现(还有很多其它强悍的功能,但需要安装脚本,生产环境不能使用)。
参考官方文档,setting-user-defined-variables 章节,设置 hostname 和 uname 变量:
set_hostname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" hostname `echo -n $(hostname) | base64`'
set_uname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" uname `echo -n $USER | base64`'
这里可以看到我们字符串里面有特殊字符,而且我们希望他们不转义,而是原样输出,可以在字符串前面增加 r 表示 raw 原始字符串。
同时我们需要把这个请求发送到当前 session,结合前面上下文的介绍和文档,我们可以这样获取当前 session 并发送命令:
app = await iterm2.async_get_app(connection)
current_tab = app.current_terminal_window.current_tab
session = current_tab.current_session
set_hostname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" hostname `echo -n $(hostname) | base64`'
await session.async_send_text(set_hostname_cmd + "\n")
set_uname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" uname `echo -n $USER | base64`'
await session.async_send_text(set_uname_cmd + "\n")
hostname = await session.async_get_variable("user.hostname")
uname = await session.async_get_variable("user.uname")
shell_cmd = "ssh %s@%s\n" % (uname, hostname)
用 Python API 可以新建窗口,但这里使用一个更直接的方式,直接点击 Duplicate Tab 菜单:
await iterm2.MainMenu.async_select_menu_item(connection, "Duplicate Tab")
一开始直接使用 await session.async_send_text(shell_cmd),但发现输出到了原来的 tab/session,看来需要获取到新创建的 tab 。本来想 Window.tabs,获取到最后一个 tab,应该就是刚新建的。
后来翻了下文档,发现还有一个更高级的实现,使用 FocusMonitor 监听 tab 的变化,获取到新增 tab_id 后再发送命令。
async with iterm2.FocusMonitor(connection) as monitor:
while True:
update = await monitor.async_get_next_update()
if update.selected_tab_changed:
tab_id = update.selected_tab_changed.tab_id
print("The active tab is now %s" % tab_id)
break
current_tab = app.get_tab_by_id(tab_id)
session = current_tab.current_session
await session.async_send_text(shell_cmd)
最后附上完整代码:
#!/usr/bin/env python3
import iterm2
# This script was created with the "basic" environment which does not support adding dependencies
# with pip.
async def main(connection):
app = await iterm2.async_get_app(connection)
current_tab = app.current_terminal_window.current_tab
session = current_tab.current_session
# 设置 hostname/user 自定义变量
set_hostname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" hostname `echo -n $(hostname) | base64`'
await session.async_send_text(set_hostname_cmd + "\n")
set_uname_cmd = r'printf "\033]1337;SetUserVar=%s=%s\007" uname `echo -n $USER | base64`'
await session.async_send_text(set_uname_cmd + "\n")
# 获取变量(有点小问题,立即获取可能没有)
hostname = await session.async_get_variable("user.hostname")
uname = await session.async_get_variable("user.uname")
shell_cmd = "ssh %s@%s\n" % (uname, hostname)
# 新建窗口
await iterm2.MainMenu.async_select_menu_item(connection, "Duplicate Tab")
# 获取到新增的 tab
async with iterm2.FocusMonitor(connection) as monitor:
while True:
update = await monitor.async_get_next_update()
if update.selected_tab_changed:
tab_id = update.selected_tab_changed.tab_id
print("The active tab is now %s" % tab_id)
break
# 登录 shell
current_tab = app.get_tab_by_id(tab_id)
session = current_tab.current_session
await session.async_send_text(shell_cmd)
iterm2.run_until_complete(main)
然后还可以把这个脚本加到 action (下文有介绍)里面,更加方便使用。当然这个脚本还有很多可以完善的地方,比如我发现设置自定义变量毕竟是通过捕获输出来设置到当前上下文的,立即获取太快了,很可能获取不到。不过从此例子可以看出,Scripts 没有做不到,只有想不到。
习惯 SecureCRT 的同学,经常用的一个功能可能就是,自定义一些命令按钮,用起来很是方便。iTerm2 也有类似的功能,叫做 Toolbelt,可以在右边显示很多功能区,默认的可能比较宽,可以自己调整大小后,点击 Toolbelt -> Set Default Width,保存当前的宽度。还能在 profile 里面配置默认打开 Toolbelt 。
Toolbelt 里面功能很多,可以都打开看看,这里介绍两个个人常用的 ---more---
全文: https://iyaozhen.com/iterm2-tips.html
大家还有什么能高级使用技巧吗?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.