探究Vim中|、<Bar>和\|的统一解析规则
Vim中
|、<Bar>和\|的行为差异实验 我整理了多组实验来对比Vim命令里|、<Bar>和\|在不同场景下的行为,下面是具体的测试过程和结论:
场景1:Shell命令
:!uname | new /bin/bash: new: command not found :!uname <Bar> new /bin/bash: Bar: no such file or directory :!uname \| new usage: uname [-amnprsv] :!uname | grep i Darwin
结论:
|会作为字面量|传递给shell。<Bar>会作为字面量<Bar>传递给shell,被当作无效的I/O重定向参数。\|会作为字面量|传递给shell。
这个场景里三者的行为逻辑很直观,输入的内容会直接传递给shell执行。
场景2:调用Shell命令的用户自定义命令
:command! A !uname | new :A /bin/bash: new: command not found :command! A !uname <Bar> new :A /bin/bash: new: command not found :command! A !uname \| new :A usage: uname [-amnprsv] :command! A !uname | grep i :A Darwin :command! A !uname <Bar> grep i :A Darwin
结论:
|和<Bar>行为一致,都会作为|传递给shell执行管道操作。\|则会作为字面量\|传递给shell,导致uname命令因参数错误报错。
场景3:调用Shell命令的映射
:map ,a :!uname | new<CR> ,a # 执行:map命令时就创建了新窗口;按下,a时,命令行模式会输入`!uname` :map ,a :!uname <Bar> new ,a # 按下,a时,命令行模式会输入`:!uname | new` :map ,a :!uname \| new ,a # 按下,a时,命令行模式会输入`:!uname | new`
结论:
|的行为特殊,会被当作:map命令和后续Vim命令new的分隔符,导致映射定义时就执行了new,而映射触发时只执行前半部分命令。<Bar>和\|行为一致,映射触发时会被转换为|,完整执行整个shell命令。
场景4:接受参数的Vim命令
:new | vnew # 创建两个分割窗口(new和vnew分别执行) :new <Bar> vnew # 创建一个分割窗口,文件名是`<Bar> vnew` :new \| vnew # 创建一个分割窗口,文件名是`| vnew`
结论:
|是Vim的命令分隔符,用来分隔两个独立的Vim命令。<Bar>和\|会被当作new命令的字面量参数,作为文件名使用。
场景5:调用接受参数Vim命令的用户自定义命令
:command! A new | vnew :A # 创建两个分割窗口 :command! A new <Bar> vnew :A # 创建两个分割窗口 :command! A new \| vnew :A # 创建一个分割窗口,文件名是`| vnew`
结论:
|和<Bar>都会被当作命令分隔符,让new和vnew分别执行。\|则会被当作new的字面量参数,只执行单个new命令。
这个结论和场景2的逻辑一致。
场景6:调用接受参数Vim命令的映射
:map ,a :new | vnew ,a # 执行:map命令时就创建了新窗口;按下,a时,命令行模式会输入`new` :map ,a :new <Bar> vnew ,a # 按下,a时,命令行模式会输入`:new | vnew` :map ,a :new \| vnew ,a # 按下,a时,命令行模式会输入`:new | vnew`
结论:
|会被当作:map命令和后续Vim命令vnew的分隔符,导致映射定义时就执行了vnew,触发时只执行前半部分。<Bar>和\|会被转换为|,触发时完整执行两个Vim命令。
这个结论和场景3一致,本质是通过:map将按键映射为命令行模式的完整命令。
场景7:不接受参数的Vim命令
:bn | bn # 跳转到下下个缓冲区(执行两次bn) :bn <Bar> bn E488: Trailing characters :bn \| bn # 只跳转到下一个缓冲区(`\| bn`被忽略了?)
结论:
- 这个场景里
|、<Bar>和\|三者行为完全不同:|作为命令分隔符,执行两次bn;<Bar>会被当作bn的无效参数,触发报错;\|会被忽略,只执行一次bn。
场景8:调用不接受参数Vim命令的用户自定义命令
:command! A bn | bn :A # 跳转到下下个缓冲区 :command! A bn <Bar> bn :A # 跳转到下下个缓冲区 :command! A bn \| bn :A # 只跳转到下一个缓冲区
结论:
|和<Bar>都会被当作命令分隔符,执行两次bn;\|则会被忽略,只执行一次bn。
内容的提问来源于stack exchange,提问作者Lone Learner
相关产品推荐
相关产品推荐

