tmux进阶

2016/07/17 tools

前言

tmux是一个进阶终端复用软件很多强大的功能。

问题

  • 部署时,有两台机器,一般需要同时对两台机器上的文件进行编辑,同时执行一些相同的命令。为了保险起见,并且可能有时候要执行不能一开始就可以预知的命令,需要看到命令的执行过程。
  • 在终端需要复制一段文字时,经常需要用鼠标,从键盘切换到鼠标会降低效率。

对于多台服务器部署,现在一般的方法,就是如果命令比较少,就一台服务器一台来操作;如果命令比较多,就打开一个tmux会话,将会话分割成4个面板,每个面板都ssh到不同机器,然后使用tmux的同步发送功能,4个面板一起操作。这样就出现一个问题,就是每次为了搭建出这样一个环境得执行好多命令,都是重复工作。身为一个程序员,就应该将重复工作脚本化,减少人肉。

对于经常鼠标和键盘切换,为了提高效率,必须克服,用全键盘操作。

解决部署问题

tmux命令组成的准备环境的脚本

以下命令创建一个命名的tmux会话:

tmux new-session -s work

以下命令可以水平分割一个窗口,用-v代替-h就可以垂直分割,-t参数来指定一个会话:

tmux split-window -h -t development

下面这个命令是最重要的,它可以向某个会话发送shell命令。我们在这行配置的最后添加了一个C-m(Control-M),这样就向 tmux 里发送了一个回车符:

tmux send-keys -t development 'cd ~/code' C-m

但是以上命令只能发送到当前的窗口中的当前面板,如果我们需要发送到一个特定面板,就需要使用[session]:[window].[pane], window可以是序号或者名字,如以下发送命令到第一个窗口中的第二个面板:

tmux send-keys -t development:1.2 'cd ~/code' C-m

以下命令创建一个新窗口:

tmux new-window -n code -t development

有了以上命令,我们就可以完成一个脚本,如下:

NAME=deploy_test
tmux has-session -t $NAME
if [ $? != 0 ]
then
    tmux new-session -s $NAME -d
    tmux split-window -v -t $NAME
    tmux split-window -h -t $NAME:1.1
    tmux split-window -h -t $NAME:1.2
    tmux send-keys -t $NAME:1.1 'ssh test100' C-m
    tmux send-keys -t $NAME:1.2 'ssh test101' C-m
    tmux send-keys -t $NAME:1.3 'ssh test132' C-m
    tmux send-keys -t $NAME:1.4 'ssh test133' C-m
    tmux set synchronize-panes
    tmux send-keys -t $NAME 'cd /home/hzw/git' C-m
fi
tmux a -t $NAME

运行上面的脚本,我们就打开了一个tmux会话,里面有一个窗口,这个窗口被分割成4个面板,每个面板都ssh到一台不同的服务器,然后设定了同步发送功能,对一个窗口键入的命令,也会被发往其它窗口。这样我们就可以交互式的同时和4台机器操作。而且操作结果也一目了然。

工作开发环境

由上面的方式如法炮制,我就可以搭建出一个开发环境,所有窗口都准备好了。这个环境打开了5个窗口,第1个窗口切换到代码目录,第2个连接到mongo,第3个连接到MySQL,第4个查看日志文件,第5个进入虚拟环境,可以执行脚本。

NAME=wtest
tmux has-session -t $NAME
if [ $? != 0 ]
then
    tmux new-session -s $NAME -n code -d
    tmux new-window -n mongo -t $NAME
    tmux new-window -n mysql -t $NAME
    tmux new-window -n log -t $NAME
    tmux new-window -n stat -t $NAME
    tmux send-keys -t $NAME:code 'cd code/test' C-m
    tmux send-keys -t $NAME:mongo 'test' C-m
    tmux send-keys -t $NAME:mysql 'db_reader' C-m
    tmux send-keys -t $NAME:log 'cd ~/project/test/var/log; tail -f root.log' C-m
    tmux send-keys -t $NAME:stat 'cd ~/project/test; source ~/project/test/virtualenv/bin/activate' C-m
    tmux select-window -t development:code
fi
tmux a -t $NAME

更进一步

线上的操作是要切换到一个admin账号上去的。一般这种输入su admin,然后输入密码的操作都是要手动交互式的进行的。我一直在想能不能将这个过程能够自动化。

直到发现except这个Linux命令行工具,expect是一个用来处理交互的命令,借助expect,我们可以将交互过程写在一个脚本上,使之自动化完成。 了解了except大体的用法后在目标服务器上写下如下脚本:

#! /usr/bin/expect

set timeout 5
spawn su admin
expect "Password: "
send "******\r"
send "cp /home/hzw/source/test/*.jar /home/admin/project/test/jar/\r"
send "sudo -E /home/admin/project/test/init.d/test_initd.sh restart\r"
send "exit\r"
expect eof
  • 其中spawn表示开始执行一个交互式命令。
  • expect "Password: "表示这个交互式命令期望的输出。
  • expect "Password: "表示发送密码。
  • 接下来都是发送执行的命令。
  • 最后退出。

执行以上脚本,我们就可以切换到admin账户,执行一些命令,然后退出。

配合tmux,我们可以把这条命令的执行写到tmux的启动脚本里,这样当我们打开这个tmux环境时,它会切出4个窗口,每个窗口都会ssh到一台机器,切换到一个账户,一般我们可以选择不退出,停留到切换后的界面,然后让我们操作。当然我们也可以直接执行命令后退出,达到部署的自动化,不过当然部署的自动化的话,就不需要tmux了。

解决复制问题

我们很多人都是用vim来进行编程,所以都会比较熟悉vim的复制方式,要是tmux也能这样复制就好了。

好在tmux就可以支持vim类似方式的复制,只需要将一下一句话放在配置文件中:

setw -g mode-keys vi

然后我们按下Ctrl-a [进入复制模式,接下来整个终端就好像是在一个vim环境中。我们可以使用vim常见的hjkl进行移动,使用/?进行搜索。

现在就可以复制了,但是tmux里复制的快捷键和vim的不一样,我们可能不熟悉,没关系,做一下配置,映射一下就可以了,如下:

unbind p
bind p paste-buffer
bind -t vi-copy 'v' begin-selection
bind -t vi-copy 'y' copy-selection
  • 第一句解除p的绑定。
  • p映射为黏贴。
  • v映射为开始复制。
  • y映射为拷贝。

有了以上配置,我们就可以使用vim的方式来进行复制了,告别鼠标,生产效率大大提高。

小结

  • 可以在 shell 里使用 tmux 的每个命令,这就意味着你可以编写脚本来自动化 tmux 的几乎所有功能。
  • 缓存区和剪贴板之间来移动文本,用键盘代替鼠标来复制,在一个很长的控制台的输出历史之间来回滚动,这些用键盘代替鼠标的方式,都可以大大提高生产效率。
  • 程序员在日常生活中总是能碰到很多重复性的工作,可能我们懒惰一下,就过去了,每次就花那么点时间,但是利用脚本让这些重复工作脚本化可以大大节约我们的时间。

Search

    Table of Contents