vim:如何插入 shell 命令的输出?

vim:如何插入 shell 命令的输出?

假设我想编辑一个新的 libvirt XML 文件:

virsh dumpxml machine1 > machine2.xml

然后我用打开文件vim

vim machine2.xml

然后我想更改 UUID。现在这样做,我用

:r ! uuidgen

但新的 UUID 会插入到当前行下:

<uuid>6r123ttz-6t01-356t-1y7h-g7oe196c8u3m</uuid>
e67baf90-751b-4aea-a14b-aca1b881542b

如何插入uuidgen命令的输出进入当前行,所以如果我有

<uuid></uuid>

(光标在 之间><),然后,通过执行uuidgen我得到

<uuid>e67baf90-751b-4aea-a14b-aca1b881542b</uuid>

问题是:是否可以使用:rvim命令而不添加新行?

答案1

:read是一个前命令;不幸的是这些总是有效完整的线路。您要么必须先拆分,然后再加入前面和后面的行,要么使用不同的命令来解决这个问题。

:help i_CTRL-R命令可以插入任意寄存器内容。有一个特别的表达式寄存器:help quote=) 执行任何 Vimscript 表达式并使用其结果。最后,system()函数执行外部命令并返回其输出。

因此(在插入模式下)<C-R>=system('uuidgen')<CR>将在当前位置插入命令的输出。不幸的是,输出有一个尾随换行符,并且该换行符被保留,因此</uuid>移动到下一行。为了避免这种情况,您可以通过system('uuidgen')[0:-2]substitute(system('uuidgen'), '\n$', '', '')作为表达式截断输出。

对于重复插入,表达历史可用于调用最后一个表达式(按<Up>);为了更加舒适,您可以为整个事物定义一个映射。

答案2

我玩了一下,这并不完全符合你的要求,因为 :r 总是会输入换行符。但它应该做你想要的结果。

:.!UUID=`uuidgen` ; echo "<uuid>$UUID</uuid>"

它将标准输出放在当前行(而不是光标处) - 智能是通过正在调用的命令完成的。

答案3

fu! SetBang(v) range
        if a:v == 1
                normal gv
        endif
        let l:t = &shellredir
        let &shellredir = ">%s\ 2>/dev/tty"
        let @" = join(systemlist(input("\"!"))," ")
        let &shellredir = l:t
endf
nnoremap "! :cal SetBang(0)<cr>
xnoremap "! :cal SetBang(1)<cr>

每次按下"!,都会提示用户输入命令,并且“未命名”"寄存器将被填充。然后,您可以照常插入它,在P正常或可视模式下,在Ctrl-R"插入模式下等。

例如,有文本(插入符号由 表示|):

<uuid>|</uuid>

并按"!uuidgen<Enter>P将在插入符号处插入新的 uuid。

您当然可以使用其他绑定来代替"!.

答案4

您还可以直接编辑 XML,甚至无需使用vim.

例如,<uuid></uuid>作为文件的一部分给出,您可以插入或更新该值:

echo '<uuid></uuid>' |
    xmlstarlet edit --update '//uuid' -v "$(uuidgen)"

输出

<?xml version="1.0"?>
<uuid>79cc09da-a256-46d5-9974-9073cf9d7a9a</uuid>

这可以让您对虚拟机定义进行模板化并以编程方式对其进行自定义。

相关内容