vim随记

Aaron是一个Vim忠实爱好者。无论是写文档还是一些简单的程序,Aaron都倾向于使用Vim来完成。

本文用以记录Aaron在日常使用Vim的过程中遇到的问题和解决方法。

分屏调整命令

  • Ctrl + w + =: 使分屏拥有相同尺寸。
  • Ctrl + w + +: 增大分屏尺寸。
  • Ctrl + w + -: 减小分屏尺寸。

使用场景:将vim全屏后,分屏线不在屏幕中部。可用上述第一个命令加以调整。

文件重命名

:f filename: 将当前文件重命名为filename。

用自增的数字来进行替换

今天写代码遇到一个场景。我需要为5个测试文件写JUnit单元测试代码。测试文件在文件系统中的存储是:

$ tree .
├── testfile1
│   └── testfile1.c
├── testfile2
│   └── testfile2.c
├── testfile3
│   └── testfile3.c
├── testfile4
│   └── testfile4.c
└── testfile5
    └── testfile5.c

而我IntelliJ IDEA中已有的代码片段是:

private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";

于是愉快地使用yy 5p复制,然后粘贴5行。效果如下:

private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";
private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";
private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";
private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";
private String test_KB_27_02_08 = kbCase + "/S_27_02/testfile8/testfile8.c";

那么问题就来了。我应该如何把第75行的8替换成1,76行的8替换成2,以此类推呢。

其实之前遇到过这样的问题。但是没有进行整理。这也说明了写博客的重要性。最终的问题的解决仅仅使用了如下的一条命令:

:let i=1 | 75,79 g/8/s//\=i/g | let i+=1

let i=1定义了i的初值;

75,79 指定了替换的行号范围,若要替换每一行,则可以用1,$或者%

g/8/s//\=i/g查找每行出现的8,并将其替换成当前的i。我很少使用g命令,但此处必须用g命令,不能改为s/8/\=i/g。原因是s(substitute)命令是同时对多个匹配到的行进行替换,由此就不能产生所要的递增的效果。

let i+=1 每次g命令匹配成功并执行相应操作后,将i自增。

批量文件重命名

今天遇到一个问题。从用例集中自动导出的文件的命名格式都是case + 数字形式的,而我本地的测试文件都是以testfile开头的。所以我需要将文件名做批量替换。

$ tree .
.
├── case10.c
├── case11.c
├── case12.c
├── case13.c
├── case14.c
├── case1.c
├── case2.c
├── case3.c
├── case4.c
├── case5.c
├── case6.c
├── case7.c
├── case8.c
└── case9.c

我的需求可以通过rename命令来完成,如下:

$ ls
case10.c  case12.c  case14.c  case2.c  case4.c  case6.c  case8.c
case11.c  case13.c  case1.c   case3.c  case5.c  case7.c  case9.c
$ rename 's/case/testfile/' *.c
$ ls
testfile10.c  testfile13.c  testfile2.c  testfile5.c  testfile8.c
testfile11.c  testfile14.c  testfile3.c  testfile6.c  testfile9.c
testfile12.c  testfile1.c   testfile4.c  testfile7.c

然后我希望将每个文件都移到同名的文件夹下,例如testfile1.c移入testfile1中,testfile2.c移入testfile2中,以此类推。

最终在StackOverflow上找到了答案:

$find . -name "*.c" -exec sh -c 'mkdir "${1%.*}" ; mv "$1" "${1%.*}" ' _ {} \;
$tree .
.
├── testfile1
│   └── testfile1.c
├── testfile10
│   └── testfile10.c
├── testfile11
│   └── testfile11.c
├── testfile12
│   └── testfile12.c
├── testfile13
│   └── testfile13.c
├── testfile14
│   └── testfile14.c
├── testfile2
│   └── testfile2.c
├── testfile3
│   └── testfile3.c
├── testfile4
│   └── testfile4.c
├── testfile5
│   └── testfile5.c
├── testfile6
│   └── testfile6.c
├── testfile7
│   └── testfile7.c
├── testfile8
│   └── testfile8.c
└── testfile9
    └── testfile9.c

14 directories, 14 files

Vim帮助文档中的连接跳转

  • Ctrl + ]跳入

  • Ctrl + T或者Ctrl + O跳回

Vim替换

:2 s/<pattern>/<replacement> 对第2行进行替换

:-10,+33 s/<pattern>/<replacement> 相对于现在光标位置前10行到现在光标的后33行

:-10;+33 s/<pattern>/<replacement> 从相对于现在光标位置的前10行开始替换33行。go to some line then do how much lines

:.,$ s/<pattern>/<replacement> .表示当前行,$表示最后一行

:?<pat1>?,/<pat2>/ s/<pattern>/<replacement>行号可以用正则表达式,?<pat1>?表示向前找找到的第一个匹配<pat1>的项,/<pat2>/表示向后找。

:s<CR> 可重复上次的替换操作。<CR>表示回车。在普通模式下输入&具有同样效果

Vim global命令

:g/<pattern>/<colon command> 命令格式。<pattern>压迫匹配的正则表达式。<colon command> 对所匹配的行要执行的命令模式的命令,如替换。 eg:g/^\s/d删除所有以空白开头的行。

:g!/<pattern>/<colon command> 对不能匹配<pattern>的行进行操作。eg:g!/^\s/d删除所有不以空白开头的行。

:g/<pattern>/ :normal <normal command> 采用g命令执行一个普通模式的命令。

Vim对齐控制

:left 左对齐

:center 居中

:right 右对齐

Vim正则表达式

\d 数字

\s 空白,包括空格和制表符

Vim yank & delete

yw 复制一个单词

yp 复制一个段落

ys 复制一个句子

yap 复制一个段落,并包含段落后面的空行。astands for ambient

yip 复制一个段落,不包含段落后面的空行。i stands for internal

ya{ 复制{}之间的部分, ya[复制[]之间的部分, 以此类推,ya(/ya</ya'

Vim branches undo/redo

:earlier <time offset> 回到之前的版本,eg: :earlier 30m回到半小时前的版本。s/m/h/d分别表示秒分钟小时天

:later <time offset> 回到后来的某个时间点的版本。

Vim Buffer切换

:ls 查看存在的buffer

:bn 切换下一个buffer

:bp 切换上一个buffer

:b number 根据编号切换buffer,例如:b1切换到编号为1的buffer

:b# 切换最近使用的buffer

Ctrl-6 切换最近的buffer

bdelete <path/to/file> 删除某个缓冲区

bwipeout <path/to/file> 彻底删除某个缓冲区。

复制指定行的内容到某一行

:24,36 copy 38 将24到36行的内容复制到第38行。实际上是copy命令。也可以写成co

文件编码

:set fileencoding 查看文件编码

:set fileencoding=utf-8 将文件转为utf-8编码

调整分屏尺寸

Ctrl-w +/Ctrl-w - 增加/减少水平分屏尺寸

Ctrl-w >/Ctrl-w < 增加/减少竖直分屏尺寸

将行首的若干空格替换为下划线

s/^\(\ \+\)/\=repeat('_', strlen(submatch(1)))/

这里用到的几个内置函数:

  • repeat( {expr}, {count}) 将一个表达式重复若干次
  • strlen( {expr} ) 返回给定字符串的长度,以字节为单位
  • submatch( {nr} ) 子匹配。相当于正则表达式中的反向引用。只能用在:substitute命令的参数中

其他

% 表示当前文件

:w !sudo tee % 写入只读文件

写于2015年09月19日