使用变量进行vi替换并结合Here Document使用

1. 在vi中使用变量对文件内容进行替换

源文件file:只包含六个整数


执行变量替换命令:


其中,“:%s/1/\=$JAVA_HOME/g "中需要注意的是"\=$JAVA_HOME"

\= 指示后面为一表达式,而$JAVA_HOME为系统中的环境变量,标识了java主目录。


====================================================================================

我们可以在vim的帮助文档中找到对 \= 的解释。

我们在vi中敲命令":h substitute",打开帮助文档到substitute的位置。

可以看到,替换命令的格式是:

:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]

其中,{string}是要替换成的目标。

我们在这个帮助界面中再输入命令"/\\=",寻找 \= 符号。

可以看到有这样一句话:"when the {string} starts with "\=" it is evaluated as an expression."

====================================================================================


这样,vi使用变量进行替换的功能就了解了。我们再来做一些尝试。

首先,我们将$JAVA_HOME用双引号括起来,并替换掉数字2。


可以看到,用双引号括起来后,双引号里面的字符串不再进行参数展开。(单引号也一样)


我们再进行更加复杂的尝试。


可以看到,s(也即substitute)命令在遇到double-quote时,便将quote中的字符串作为表达式结果,而在遇到"$"号时,则会进行变量的展开。

上图命令中的"."看起来应该是连接字符串的作用,但是还未在文档中找到专门的说明。 

如果使用 ${JAVA_HOME}会导致invalid expression的错误发生,也即{}在s命令中无效。


2. 在here document中使用vi替换命令

编写的脚本如下:

脚本1:脚本中替换的命令是基于上文中的内容写的,这个脚本尝试将数字4更换为java主目录。脚本中从vi开始到最后的感叹号属于 "here document"。

执行脚本1,因为没有重定向vi的输出,所以最终的结果会直接显示在终端上,如下所示:



一开始的vim警告很直观,输入确实不是来自终端,而是来自文件。

但是最终显示的结果,数字4没有被替换掉。那是出了什么问题呢?


先来看一下脚本2。

脚本2: 将str赋值为字符串“123”,将数字4替换为123。


执行脚本2,我们看到替换成功了。



脚本1中str取的值是java主目录,也即"/usr/local/jdk6",替换失败了;脚本2中,str取的值是"123",替换便成功了。

立即就可以察觉的是,失败的案例中,str的值包含了"/"符号。我们再去查看vi的帮助文档,可以看到在substitute的帮助文档中,有这样一段话:

"Be careful: The separation character must not appear in the expression!
Consider using a character like "@" or ":".  There is no problem if the result
of the expression contains the separation character.
"

java主目录中的"/"确实和我们使用的separation character是冲突的,但是如红字中所说,分隔符只有出现在表达式本身才会有影响,如果表达式的结果包含分隔符是没有关系的。$str被展开为java主目录后是包含了分隔符,但是$str本身并不包含分隔符。


其实导致失败的原因应该是这里由shell提前执行了一次变量的展开。

也即":%s/4/\=$str/g"在脚本1中先由shell展开为:":%s/4/\=/usr/local/jdk6/g",再交由vi执行替换命令。可以看到,此时,\=后面包含的串中出现了分隔符,所以导致了替换失败。

而":%s/4/\=$str/g"在脚本1中先由shell展开为:":%s/4/\=123/g",再交由vi执行替换命令,vi会将\=后面的123解释为一个字符串,所以替换成功了。


如果尝试将str=123u(或者str="123u"),也即使str包含任意字母,则替换失败,提示123u为invalid expression。

经测试,如果出现在 \= 后的为纯数字串,则vi将其作为基础字符串;若出现在\=后的串中包含字母,则会被当做一个变量。

str=123u和或者str="123u"测试失败,说明在赋值时不论有没有引号,":%s/4/\=$str/g"均被shell展开为":%s/4/\=123u/g",并交给vi。此时,vi会将\=后的123u当做一个变量,并再次尝试展开,便得到了invaild expression的错误。


总之,导致脚本1失败的原因就是shell已经做了一次变量扩展,再将扩展后的命令交给了vi。

这样的话,竟然shell已经对变量扩展了,那么交给vi的命令中也就没有变量了,而是直接的字符串,也即此时"\="符号是多余的了。

在脚本1中,\= 号本来是vi用来标识对$str的解释的,但$str已经被shell展开了,"\="明显多余了,所以不再需要。

在脚本2中,有没有\=号的效果是一样的。因为":%s/4/123/g" 和 ":%s/4/\=123/g"的执行效果相同。

我们在脚本1的基础上,将 "\="号删除。此时,我们仍需要将替换命令的分隔符换掉(不要忘记了上文的"Be careful"),形成如下脚本:

脚本3:尝试将5换成java主目录


执行脚本,我们得到了期望中的结果。


我们再来看一个脚本:

脚本4:尝试将file中的6全部替换为java主目录路径。


之后,我们看到file中的6全被替换为了java主目录路径。

这是因为:%s!6!\="$str"!g被shell展开为:%s!6!\="/usr/local/jdk6"!g并交由vi执行替换了。

上文说过"\="号后,双引号括起的内容被直接当做字符串处理。


总结一下:

1. vi 中 \= 用来标志后面为表达式;

2. 注意 \= 后的表达式本身(而非结果)不能与分隔符相同,一般需考虑采用其他分隔符;

3. 在shell中使用Here Document时,变量会先被shell展开再交由指定命令处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值