配置高效科学Linux开发环境

Posted by int32bit on October 3, 2016

记得2010年刚读大二,在大神@btw的指导下折腾Linux,从那时开始一直使用Linux学习和工作,折腾了不少Linux发行版,其中包括Ubuntu、Debian、Mint、Gentoo、LFS、CentOS等,现在已经完全离不开Linux环境,沉陷在Linux的工作方式中,思维方式也完全Linux化,遇到问题时第一直觉是想有没有什么命令加上管道组合或者正则匹配来解决,而不是想到需要打开什么面板点击什么按钮。当然我并不是终端命令的偏执狂,同时也喜欢酷炫的UI界面,比如Java开发,我个人偏向于使用一款方便友好的IDE,而没有选择在终端下调用vim,尽管可以通过各种vim插件实现类似IDE的功能。但C、python我却更偏向于使用vim,而没有使用任何IDE,即使用了也会想想能不能调成vim模式,比如pycharm、sublime等。

Linux是自由和开放源代码的类UNIX操作系统,除了内核本身,在此之上的应用也大多数是开源自由的,自由意味着你可以选择用或者不用,你可以自由地从多种相同功能的应用软件中选择一款自己喜欢的,没有任何捆绑,没有任何强制,也不会偷偷给你推销个全家桶。开源意味着你可以随时拿到完整的应用软件源代码,你完全可以知道你所使用的软件到底做了些什么,有没有后门,有没有恶意扫描,会不会偷偷把你的信息泄露,只要有代码,一切尽在掌控,你甚至可以根据自己的需求随意修改源代码定制化自己的专属功能。Linux软件大多数会遵循KISS(Keep it Simple, Stupid)设计哲学,大多数的shell命令都会遵循以下原则:

本文总结了使用的Linux的一些环境配置和使用经验,github中托管了我使用的所有dotfiles文件,项目地址为dotfiles:A set of vim, zsh, git, and tmux configuration files,文中涉及到的所有配置项以及配置脚本均在该项目中托管,dotfiles文件以及配置脚本主要便于自己能够在新环境中快速重现自己的个性环境,也欢迎同仁们共同讨论和分享。本文不会详细介绍各个软件或者命令的使用方法,因为这很容易地通过man手册或者google获取,本文的目的仅仅是谈谈我自己的一些使用经验和个性化配置。

1 ssh

如果有可能的话,建议使用mosh替代ssh,mosh基于UDP传输,比ssh更稳定、更容忍网络故障和延迟,不会像ssh那样频繁掉线或者出现pipe broken错误。它自带会话保持功能,因此可能就不需要ssh到远程服务器后开启多个screen或者tmux。但是很多服务器目前并没有安装mosh,使用ssh的还是占主流,并且mosh也不支持ssh-agent、X11-forward等,因此短期内还不会存在mosh完全取代ssh的可能。因此本文还是需要总结下ssh的一些配置。

1.1 快速配置

在ssh目录下直接运行setup.sh脚本即可,不需要其它额外配置。

1.2 连接复用

通常我们ssh连接到一台服务器退出后连接即断开,再次连接时会重新建立连接,需要重新校验密钥或密码。如果使用密码登录,则需要反复输入密码,在需要管理大量远程服务器时效率极低。密码是静态不变使用sshpass可以避免每次输入密码,但显然这是极其不安全的。如果密码是动态生成的,比如跳板机,每次需要打开手机查看动态密码非常麻烦。

ssh连接复用是指一旦成功建立远程主机的ssh连接会保持一段时间的session,在session有效期内可以复用该连接,不需要重新做身份验证。这有点类似sudo命令,第一次输入密码后,再次执行sudo命令不需要输入密码了。

ssh连接复用配置如下:

第一次建立连接时会在ControlPath目录下生成一个socket文件,文件格式为%h-%p-%r, 其中%h表示远程主机名,%p指连接的端口,%r是登录用户名。

注意:

1.3 保持会话

ssh成功登录到一台服务器即创建了一个新的会话,当该会话超过一定时间内没有接收任何请求时,会话会自动断开连接。有时这不是我们所期望的,比如ssh到一台服务器后,google下资料回来发现ssh断开了。

为了保持会话,可以设置ssh客户端每隔一段时间自动发送一个心跳,比如每隔60s发送一个hello包。

我们还可以设置允许发送心跳的最大数量ServerAliveCountMax,当超过这个数量仍然没有接收用户响应时则会自动断开连接。

1.4 禁用主机key校验

ssh连接时会检查主机的公钥,如果第一次连接主机会显示该主机的公钥指纹,需要用户确认是否信任该主机。

如果我们跑后台脚本时就会进程就会立刻堵塞直到接收用户输入,导致后台脚本不能正常运行。

如果确认信任该主机并且保证不会被劫持攻击的话,可以跳过主机公钥校验,配置如下:

如果通过shell连接,不建议禁用公钥校验。

2 tmux

2.1 快速配置

运行tmux/setup.sh脚本即可,不需要其它额外配置。

2.2 配置说明

prefix键为默认的ctrl-b,个人感觉ctrl-b挺方便的,很多人设置为ctrl-a,这会与在命令行下快速移动光标到行首冲突,需要按两下ctrl-a

设置分屏:

这样容易记住,|垂直分屏,-水平分屏。

禁用windows自动命名,主要是它会覆盖原来的名字:

设置windows从1开始索引:

重新加载配置文件(prefix+r):

打开一个临时窗口查看man手册:

只需要输入prefix+/,然后输入需要查询的命令即可。

2.3 主题方案

选用的主题是Solarized,参考Making tmux Pretty and Usable - A Guide to Customizing your tmux.conf,为了和iterm以及vim集成,手动调节了部分颜色,包括panel boder颜色以及windows菜单颜色等。

status bar设置在顶部,为了避免和vim status重叠。

最终效果如图:

tmux

3 vim

注意:当加载太多插件时,vim启动会很慢,并且vim 8以前插件加载都是同步的,必须等待插件执行完才能继续下一个任务. 因此我把自动生成tags功能默认是关闭的, 避免每打开一个文件都要卡顿几秒。另外可以使用neovim替代vim,支持异步加载插件,响应速度相对原生vim快很多。

3.1 Setup

dotfiles/vim目录下运行setup.sh即可自动完成配置,配置过程中会自动安装vundle以及插件。

配置过程中可能出现Solarized方案不存在错误,由于该主题方案还没有安装,直接忽略该错误即可。

除了以上配置还需要完成以下包的正确安装:

检查ctags是否安装成功:

最后配置YCM,在~/.vim/bundle/YouCompleteMe目录下运行install.py脚本。注意执行该脚本时必须已经正确安装cmakeg++python-devel等,否则会build失败。

检查是否配置成功,大多数功能一般不会有什么问题,不需要检查,唯独自动补全功能需要确定是否工作,打开一个C文件或者python文件,检查以下工作:

如果以上检查都能正常工作,则说明配置没有问题,接下来详细介绍vimrc配置文件。

3.2 全局配置

全局配置指vim原生支持的功能配置,不需要安装任何插件。

3.2.1 通用配置

3.2.2 设置Leader键

Leader键是快捷键的前缀,类似于tmux的prefix键。根据个人习惯可以自定义Leader键,有人设置为;(分号),也有人设置为空格键"let mapleader="\<space>",空格键默认功能是向右移动光标,如果设置为Leader键,恢复原来的功能需要按两次空格键。为了方便,我设置Leader键为'(单引号),当然这也会和vim自带的书签跳转冲突,不过个人很少使用书签功能,因此可以忽略这个冲突:

3.2.3 设置制表符

设置制表符占用4个空格字符,并且自动扩展为4个空格:

3.2.4 打开上次关闭文件的位置

打开一个文件时vim光标位置默认位于第一行,如果需要设置光标位于上次关闭时位置,配置如下:

注意:如果不生效,可能是由于~/.viminfo没有访问权限,需要修改owner:

3.2.5 快捷键配置

3.2.6 gvim配置

图形化vim配置,通常不需要:

3.2.7 sudo强制保存文件

有时我们编辑文件时需要root权限,但忘了使用sudo,我们可以通过在vim调用系统命令把当前缓冲区内容强制写入到当前文件中。

解释下以上这个命令,w表示write,后面不加任何参数即保存到当前文件,如果后面有文件名,则会另存为指定文件中,写入文件其实就是把当前缓冲区内容重定向到文件中,当然我们也可以重定向(管道)到另一个系统命令中作为该系统命令的输入。!表示在vim命令模式下执行shell命令,后面接的就是所要执行的命令。%可以认为是vim的一个寄存器,保存着当前打开的文件路径,因此:w其实就相当于:w %,知道这几个字符的含义后就大致知道这个命令的原理了,相当于:

为了便捷,设置了如下快捷键:

此时只需要按下Leader键'再按大写字母W就可以强制写入文件。

注意当写入成功后会有以下警告信息:

直接回车即可,保存文件后,我们使用:q!强制退出vim。

3.3 插件列表

1. Vundle

Vim bundle的简写,它是当前最流行的vim插件管理工具。虽然目前最新版vim已经内置支持插件管理了,不过鉴于目前使用的大多数还是7.3、7.4,因此本人仍使用vundle插件管理,以下所有的插件均是通过vundle管理的。

安装vundle:

在vim配置文件~/.vimrc中启用vundle:

查看插件列表:

安装插件:

或者

更新插件:

禁用插件直接在~/.vimrc注释插件即可,如果需要从本地彻底删除,运行以下命令:

或者

2. vim-powerline

主要功能是使vim底部的状态栏更美观。

3. vim-cpp-enhanced-highlight

c++语法高亮增强,支持c++11/14,增加标准库/boost类型和函数高亮。

4. vim-signature & BOOKMARKS–Mark-and-Highlight-Full-Lines

书签可视化以及书签行高亮。在命令行下输入m然后任意字母创建标签,效果如图:

vim-mark-demo

5. tagbar

taglist的增强版本,需要安装ctags包,设置的快捷键为键+t: 即按下'然后按t打开标签列表:

vim-taglist

其它配置项如下:

6. nerdcommenter

方便批量注释,能够自动识别使用的语言,比如shell使用#注释,而C语言使用/* ... */等。

使用可视化v(Shift+V)选中文本后,使用 cc注释,使用 cu取消注释:

vim-nerdcommenter

7. nerdtree

项目文件浏览,使用 f打开:

vim-nerdtree

8. YouCompleteMe

Vim自动补全插件,能够集成ctags以及jedi等,效果如图:

ycm

ycm

9. ctrlp

文件搜索功能,能够在vim上快速搜索文件并打开。在命令行模式下输入ctrl+p触发:

ctrlp

10 vim-easymotion

快速在文本中跳转,f命令的增强版,按两下Leader键和f命令组合使用,比如跳转在有a字母的位置:

此时再按高亮显示的字母即可以快速跳转到选择的位置。

效果如图:

easymotion

11. vim-surround

处理各种括号以及html标签,比如()[]()

比如把"Hello World!"删除引号转化为Hello World!,输入ds". 需要把双引号修改为单引号,输入cs"'

参考sdf13:

12. vim-bracketed-paste

在vim使用系统粘贴板粘贴代码时,vim会根据缩进语法自动格式化代码,插入多余的缩进符,这往往不是我们所预期的。比如我复制的内容为:

在vim中insert粘贴内容效果为:

vim paste

通常的做法是使vim进入paste模式:

每次粘贴复制都需要切换paste模式,这太麻烦了,而且容易忘记。我们可以利用bracketed paste mode,该模式下粘贴时会自动在两端加入特殊字符,如复制的内容如果是HelloWorld,粘贴后的内容为:

这使程序能够根据这些特殊字符判断输入是粘贴的还是用户手动输入的。vim-bracketed-paste插件正是利用了这个特性,判断如果是粘贴的内容,自动进入paste模式,内容粘贴结束,自动退出paste模式,完美解决了以上问题。

其它插件

3.4 Theme

使用Solarized主题方案。

4 zsh

4.1 配置

直接运行zsh/setup.sh,该脚本会自动安装oh-my-zsh。

全局配置

待补充。

4.2 插件列表

git

提供git常用简化别名,并且当工作目录在git项目下会自动显示所在的分支。

zsh-syntax-highlighting

语法高亮,命令错误或者命令返回错误会以不同的颜色高亮显示。

zsh-syntax

上图中sl命令不存在,因此红色高亮显示,并且显示红色,表示上条命令返回了错误码。

extract

只需要输入x+文件名就能解压缩文件,不需要知道它是tar、gz还是xz。

z

类似autojump,输入z能够查看cd历史记录以及权重,输入z 模糊路径能够快速cd到匹配的目录中。

safe-paste

默认情况下当复制粘贴文本到终端时,当遇到换行符,终端会立马执行该命令。如果同时复制多行内容,终端会把所有内容根据换行符拆分成多个命令依次执行。这显然不是我们所期望的。利用bracketed paste mode特性,终端可以通过两端的特殊字符判断输入是粘贴的还是手动输入的,从而避免遇到换行符就立马执行。

4.3 主题列表

使用默认的robbyrussell主题。

4.4 alias列表

待补充。

5 pip

使用中科大源:

注意国内的pip源偶尔会出现不稳定的情况,如果出现连接错误,需要尝试下禁用该源。本人在部署devstack时使用豆瓣和中科大源都出现过pip源连接出错问题。

6 git

注:建议使用tig命令替换git命令,详情请参考后面的附加列表。

6.1 基本配置

解决git status无法显示中文:

6.2 颜色方案

6.3 alias列表

待补充。

7 iterm

主题基于内置Solarized Dark主题定制化,最终主题在iterm目录下,效果如图:

iterm

附 非常棒的命令行工具

ag

比grep、ack更快的递归搜索文件内容。

tig

字符模式下交互查看git项目。

tig-demo

mycli

mysql客户端,支持语法高亮和命令补全,效果类似ipython,可以替代mysql命令。

jq

json文件处理以及显示,可以替换python -m json.tool

shellcheck

shell脚本静态检查工具,能够识别语法错误以及不规范的写法。

yapf

Google开发的python代码格式规范化工具,支持pep8以及Google代码风格。

mosh

可以替代ssh,连接更稳定,即使IP变了,也能自动重连。

fzf

命令行下模糊搜索工具,能够交互式智能搜索并选取。

fzf

PathPicker(fpp)

在命令行输出中自动识别目录和文件,交互式选择后使用EDTOR打开.

输出如下:

git-diff

可以光标选择文件打开或者执行命令:

fpp-demo

绿色显示的表示我们选中的文件,此时输入enter键将调用编辑器打开选中的文件,也可以按c进入命令模式,可以输入执行的命令,选中的文件将作为命令的输入文件。

pandoc

Markdown,HTML,PDF,LaTEX等文档格式之间的命令行转换工具。

支持PDF转化需要依赖pdflatex:

README.md转化为PDF格式:

htop

可以代替top命令,提供更美观、更方便的进程监控工具。

htop

axel

多线程下载工具,下载大文件时可以替代curl、wget。

axel

yum、gentoo partage等包管理工具能配置axel为下载工具替代curl。Homebrew从2013年开始提出使用axel下载,但目前好像尚未实现,参考#19802

sz/rz

ssh登录到服务器后经常需要传输文件, 通常我们会使用scp/rsync工具,或者使用ftp/nc等命令,临时解决办法还可以使用python -m SimpleHTTPServer或者python3 -m http.server开启HTTP服务器使用浏览器下载。

sz/rz能够提供更简单的交互式接口快速地和本地主机进行文件传输,也就是上传和下载文件到服务器和本地。

运行:

会立即弹出本地文件管理窗口选择保存位置,不需要输入密码。

同样地,运行:

会弹出本地文件管理工具,选择需要传输的文件,能够快速传输到当前服务器工作目录下。

注意:

常用小技巧

1. sudo !!

主要是利用了shell(bash)的History Expansion,我们使用history命令时能够列举执行的历史命令列表:

每个命令前面是命令编号,如果要重复执行某个命令,只需要输入!加命令编号即可,比如以上需要再次重启sshd服务,只需要执行:

!后面如果是负数,则表示执行前第N个命令,比如!-1表示执行上一个命令,!-5则表示执行倒数第5个命令,执行上一个命令也可以使用!!替代,即!-1!!是等价的,通常使用!!会更便捷。一个典型的场景是执行一条命令时需要root权限,忘记输入sudo了,只需要执行以下命令即可:

关于bash的History Expansion参考Linux Bash History Expansion Examples You Should Know

2. \^status\^restart\^

我们经常可能需要重复执行上一条命令,但需要修改个别参数,比如我们使用systemctl查看nova-compute服务状态:

如果我们发现服务异常,紧接下来的操作很可能是想重启下服务,此时只需要执行以下命令即可:

以上命令会自动替换为:

3. 使用编辑器编辑长命令

我们经常遇到需要输入非常长的命令的情况,此时如果在shell里直接输入会特别麻烦,并且不好处理换行情况,此时可以调用本地编辑器编辑命令,输入ctrl-x + ctrl-e即可。

4. 终端快捷键

终端下几个常见的快捷键:

一个典型场景,输了一大串命令A还未执行,发现需要执行另一条命令B,又不想开启一个新的终端,怎么保存当前输入的内容A呢,有两种方式:

  1. 使用ctrl-u剪切整行内容A,执行完B命令后,使用ctrl-y恢复,在此之前不能有其它剪切操作,否则内容会被覆盖.
  2. 使用ctrl-a移动光标到行首,输入#注释当前行内容后直接回车,这相当于注释了当前行,但在history中依然会有记录,恢复时只需要使用ctrl-p找到刚刚的命令,去掉#即可。

参考

  1. vim-sdf13
  2. 所需即所获:像 IDE 一样使用 vim

http://int32bit.me/2016/10/03/配置高效科学的Linux开发环境/