复合搜索
1 #!/bin/ksh
2 #
3 echo "Starting"
4 file=${1}
5
6 echo ${file}
7
8 if [[ ${file} = 1 ]] ; then
9 ((file=${file}+1))
10 echo "Adding one gives " \
11 ${file}
12 fi
13 echo "Ending"
14 exit
如果希望搜索出现在另一个模式或字符串后面的某个模式或字符串,不管这两个模式或字符串是否在同一行上,那么可以指定由分号 (;
) 分隔的两个搜索命令,从而执行复合搜索。例如,要想搜索出现在字符串 {file}+1
后面的字符串 echo
,应该使用 /{file}+1/;/echo/
。在 清单 6 所示的文件中,这个命令会找到第 10 行的第一个单词。
复合搜索对于寻找代码中出现在另一个命令后面的某个命令尤其有用 — 例如,在设置某个变量之后调用函数的地方。
重放搜索模式
当在文件中搜索要替换的模式时,可以让 vi 把要匹配的任何模式保存在缓冲区中;然后,在执行替换时,可以用缓冲区引用号重放它们。方法是把模式放在 \(
和 \)
之间,这会指示 vi 把模式放在编号的缓冲区(1 到 9)中。在执行替换时,可以用缓冲区引用号 \1
到 \9
引用这些缓冲区。
例如,假设要在 清单 7 所示的文件中搜索以单词 Martin 开头的行并对每个匹配添加前缀 Mr 和后缀 Wicks,那么进入命令模式,输入 vi 命令 :%s/^\(Martin\)/Mr \1 Wicks/g
,然后按回车。
清单 7. 重放搜索模式(之前)
Martin is an IT consultant. Martin likes snowboarding and mountain biking. Martin has worked on UNIX systems for over 15 years. Martin also worked for many years before that on mainframes. Martin lives in London. ~ ~ ~ ~ :%s/^\(Martin\)/Mr \1 Wicks/g
下面把这个命令分解开解释一下:
:%s
— 指示 vi 执行替换。/
— 模式分隔符。^\(Martin\)
— 寻找以字符串Martin
开头的行并把这个字符串保存在缓冲区 1 中。/
— 模式分隔符。Mr \1 Wicks
— 把找到的字符串替换为字符串Mr
,加上缓冲区 1 中的内容,再加上字符串Wicks
。/
— 模式分隔符。g
— 全局修改(即修改所有匹配的地方)。
在搜索和替换字符串中都可以使用缓冲区引用。
修改的结果见 清单 8。
清单 8. 重放搜索模式(之后)
Mr Martin Wicks is an IT consultant. Martin likes snowboarding and mountain biking. Martin has worked on UNIX systems for over 15 years. Martin also worked for many years before that on mainframes. Mr Martin Wicks lives in London. ~ ~ ~ ~ :%s/^\(Martin\)/Mr \1 Wicks/g
筛选
您可能知道,在 vi 中按 Escape,输入 :!command
(其中的 command 是要执行的 UNIX 命令),然后按回车,就可以在 shell 中执行命令。例如,:!pwd
显示编辑会话当前的工作目录。
但是,还可以把文件的一部分作为标准输入发送给 UNIX 命令,并用产生的输出替换编辑缓冲区中的相同部分。例如,如果希望在 vi 会话内对 清单 9 所示的整个文件进行排序,可以按 Escape,输入 :1,$!sort
并按回车,这让 vi 把从第一行到文件末尾($
)的所有内容传递给 sort
命令,用输出替换指定的部分。
清单 9. 在 vi 会话内执行文件排序(排序之前)
5 4 3 2 7 6 5 4 8 9 6 3 1 3 4 ~ ~ :1,$!sort
#注意:此处:1,$必不可少, 不然默认的是shell命令,且报错, 排序然后是删除重复行:1,$!sort | uniq
清单 10 显示 sort
操作的结果。
清单 10. 在 vi 会话内执行文件排序(排序之后)
1 2 3 3 3 4 4 4 5 5 6 6 7 8 9 ~ ~ :1,$!sort
另外,还可以在 shell 命令前面加上从当前游标位置开始希望操作的行数。方法是按 Escape,然后输入指定行数的数字,然后输入两个惊叹号(!!
),最后输入 UNIX 命令。
例如,把游标放在 清单 9 中第 4 行的开头,按 Escape,然后输入:
4!!awk '{print "New text",$0}'
再按回车,就会在第 4 到第 7 行(含)上加上前缀文本 New text
,见 清单 11。
清单 11. 在多个代码行前面加上新文本
5 4 3 New text 2 New text 7 New text 6 New text 5 4 8 9 6 3 1 3 4 ~ ~ !awk '{print "New text",$0}'
可以使用管道分隔符(|
)把 UNIX 命令连接在一起,从而在 vi 会话中执行复杂强大的筛选。例如,假设要把当前 vi 会话的编辑缓冲区中的文件内容替换为每行的第一个空格分隔的字段,按升序排序并转换为大写,那么在按 Escape 之后输入:
:1,$!awk '{print $1}' | sort | tr [:lower:] [:upper:]
保存部分内容
可以保存当前编辑的文件的部分内容,方法是按 Escape,然后输入 :start,endw file
,其中的 start 是当前文件中要保存的第一行,end 是要保存的最后一行,w
表示希望写到另一个文件中(或者覆盖现有的文件),file 是指定的部分要保存到的文件。对于最后一行,可以使用 $
表示文件的末尾。可以在 w
后面使用两个大于号(>>
)表示希望把内容附加到文件中而不是覆盖文件。清单 12 中的示例把第 6 到第 9 行(含)附加到文件 /tmp/newfile 中。
清单 12. 把文件的部分内容保存到另一个文件中(附加而不是覆盖)
1 # 2 # Internet host table 3 # 4 ::1 localhost 5 127.0.0.1 localhost loghost 6 192.168.0.6 centos5 7 192.168.0.10 appserv 8 192.168.0.11 webserv 9 192.168.0.12 test 10 192.168.0.5 solaris10 # Added by DHCP ~ ~ ~ :6,9w >> /tmp/newfile