iTerm2 的优点这里不做赘述了,第一次使用的话可以先看看官网的介绍:features、Highlights for New Users。本文主要是结合实际使用场景,介绍一些进阶使用技巧(基本的 Oh My Zsh、rzsz 等配置就不重复说明了)。
目录
跳板机自动登录
现在很多公司登录服务器都需要先登录到一个跳板机然后再登录到目标机器,每次输入密码(一般还是动态的)很麻烦。一般的教程推荐使用 expext 解决这个问题,这里介绍一个更简单、直接的办法。
首先,要先解决登录到跳板机的连接复用问题,这个输入 ssh 本身的范畴,一般教程都是说在 ~/.ssh/config 增加下面的配置:
1 2 3 | host * ControlMaster auto ControlPath ~/.ssh/master-%r@%h:%p |
但这样有个问题,iTerm2 第一次登录的 tab 关闭后,就失效了,再登录就又要密码了。其实再增加一个配置即可。
1 2 | 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 自定义脚本章节有介绍。
Scripts
iTerm2 还有个非常强大的功能,就是支持自定义脚本,而且新版的脚本可以用 Python 写,只要想象力够丰富,可以实现很多功能。动手前可以先多看几遍官网的文档说明:Scripting Fundamentals。
先介绍一些基本概念,上下文按层级划分:app、window、tab、session,如下图所示:
我们做一些操作的时候需要明白操作的上下文对象,那么一个对象具体可以做什么呢,需要看具体文档:https://iterm2.com/python-api/。可以按照官方示例做一遍,官网也有很多例子可以参考。
下面我们尝试用 script 来实现增强版的 Duplicate Tab
的功能,能复制当前已登录的服务器。模拟我们手工操作的过程,可以把步骤分为 3 部分:
1. 获取当前user/hostname
一开始我看到 tab 的名称都能显示当前 host,但查了一番资料未果。中间查阅文档发现 iTerm2 内置了很多变量,其中有 hostname
,但试了下只能获取到 Mac 电脑的 hostname。后来又想我在服务器上执行 hostname 命令,然后怎么把这个结果传递给 iTerm2。
一通翻文档,发现了 iTerm2 有个特殊的 Escape Codes 功能,简单来说就输出包含一些特殊字符的时候,屏幕上不会显示,但 iTerm2 会捕获这种逃逸字符,然后实现一些特殊功能。比如强大的 Shell Integration 就是基于此实现(还有很多其它强悍的功能,但需要安装脚本,生产环境不能使用)。
参考官方文档,setting-user-defined-variables 章节,设置 hostname 和 uname 变量:
1 2 | 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 并发送命令:
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
2. 新建一个窗口
用 Python API 可以新建窗口,但这里使用一个更直接的方式,直接点击 Duplicate Tab
菜单:
1 | await iterm2.MainMenu.async_select_menu_item(connection, "Duplicate Tab") |
3. 登录记录的服务器
一开始直接使用 await session.async_send_text(shell_cmd)
,但发现输出到了原来的 tab/session,看来需要获取到新创建的 tab。本来想 Window.tabs,获取到最后一个 tab,应该就是刚新建的。
后来翻了下文档,发现还有一个更高级的实现,使用 FocusMonitor 监听 tab 的变化,获取到新增 tab_id 后再发送命令。
1 2 3 4 5 6 7 8 9 10 | 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) |
最后附上完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #!/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
没有做不到,只有想不到。
Toolbelt
习惯 SecureCRT 的同学,经常用的一个功能可能就是,自定义一些命令按钮,用起来很是方便。iTerm2 也有类似的功能,叫做 Toolbelt,可以在右边显示很多功能区,默认的可能比较宽,可以自己调整大小后,点击 Toolbelt -> Set Default Width,保存当前的宽度。还能在 profile 里面配置默认打开 Toolbelt。
Toolbelt 里面功能很多,可以都打开看看,这里介绍两个个人常用的:
Snippets
简单来说就是一些脚本片段,好记性不如烂笔头,Linux 有些命令参数很长,用的时候敲起来很麻烦,而且容易记不住。比如统计当前目录下的文件大小的命令:du -h --max-depth=1,就可以建一个 snippet(代码片段),双击就能执行,很是方便。
Actions
可以发现 iTerm2 菜单项非常多,有些功能需要点几层进去操作,非常麻烦。这是就可以定义一个 action(动作),方便操作(特别是需要来回切换的)。
其它实用功能
前面介绍的大功能可能有点多,来点个人认为比较实用的小功能。
命令结束通知
非生成环境可以使用 Shell Integration 的 Alert on next mark 功能,命令运行完后发一个通知
生产环境不能使用 Shell Integration,但还是可以借助 Escape Codes 来自己发送通知。参考“Post a notification”章节,新建一个 snippet:
printf "\033]9; cmd complete \007"\n
然后在输入命令后,点击执行此 snippet,则在前面的命令运行完成后,会执行通知命令,达到通知的目的。
而且通知还能自动带上之前执行的命令,非常的 nice。
鼠标滚动查看日志
我们线上看日志一般是 less 命令,使用 j/k 翻找,比较麻烦,当你尝试滚动鼠标时,iTerm2 会提示你是否开启 Scroll wheel sends arrow keys when in alternate screen mode
,如果不小心关闭了,可以再设置中再开启。
显示操作时间轴
View -> Show Timestamps,就能再右边显示一个操作的时间轴,这样就能很方便的看见之前的命令是什么时候执行的,有些时候排查问题特别方便。但这个会遮挡右边的显示,我们可以定义一个 action,方便切换开关。
本文介绍只是一些个人常用的技巧,也很有限,还有很多其它好的功能等待挖掘。最后引用官网的一句话,“iTerm2 is a terminal emulator for Mac OS X that does amazing things.”,发挥自己的创造性做一些 amazing things 来提高效率吧。
参考资料
linux配置超时不操作自动退出登录TMOUT,https://learnku.com/articles/52161
iTerm2 使用笔记 - 小蒋不素小蒋,https://www.cnblogs.com/xjnotxj/p/10272591.html
iterm2 怎么添加自定义按钮?https://www.v2ex.com/t/475333