vim 可以在不将换行 (^@) 字符视为 "Enter" 按键的情况下回显寄存器的内容吗?

Can vim echo the contents of a register without treating linefeed(^@) characters as "Enter" key press?

我有一些文本行要输入到寄存器中,然后将寄存器的内容回显到生成 vim 进程的终端,以便文本在终端中可见window 在 vim 退出后。

我可以用一行文本让它正常工作,但是一旦添加 newline/linebreak,所有尝试都失败了。

使用示例文件包含:

1个
2 ab
3 abc
4 abce
5 个 abcef
6 abcefg

首先我将文件内容放入寄存器("m) via ":%y m" 然后我尝试 ":exe '!echo '@m"

这会将第一行文本回显到终端

一个

但是 vim 将字母 "a" 后的第一行 feed/break 视为按回车键,因此它会抛出以下错误消息

E492: 不是编辑器命令:abce^@abcef^@abcefg^@^@

我 运行 在“:debug”模式下执行以下命令,希望用换行符 (\n)

替换 ^@ 字符

:回声替代(strtrans(@m),"^@",'\n',"g")
:echo substitute(strtrans(@m),'^@','\n',"g")

我试过双引号和单引号,我试过按字面输入脱字符和符号,以及使用特殊字符 CTRL-V+CTRL-J 不幸的是,在调试模式下,我可以看到输出始终如下:

a^@ab^@abc^@abce^@abcef^@abcefg^@^@

printf 也是如此。 我已经复习了换行符、空字符的歧义,以及 vim 如何在寄存器中处理这些,但我不清楚我想要实现的目标是否合理。

:h nl-used-for-nul说明换行符'\n'被Vim显示为^@。所以,是的,正如您已经说过的,您将实际的换行符发送到 shell.

接下来,将一个字符'\n' (ASCII 0x0a) 替换为两个字符"\n" (0x5c 0x6e) 的一般思路也是正确的。您希望 shell 接收 foo\nbar

:echo substitute(@m, '\n', '\n', 'g')
a
ab
abc
abce
abcef
abcefg

输出显然仍然包含实际的换行符,所以我们必须转义这些。

:echo substitute(@m, '\n', '\n', 'g')
a\nab\nabc\nabce\nabcef\nabcefg\n

这看起来不错!那么,让我们尝试一下您想到的整个命令:

:execute '!echo' substitute(@m, '\n', '\n', 'g')
anabnabcnabcenabcefnabcefgn

Press ENTER or type command to continue

嗯?嗯,:execute 评估字符串,因此 消耗 "one level of strings"。因此,我们必须再次转义我们的换行符,而我们必须 double 每个 "level of strings".

的转义量

所以,我们不仅需要a\nab\nabc,我们还需要a\nab\nabc:

:echo substitute(@m, '\n', '\\n', 'g')
a\nab\nabc\nabce\nabcef\nabcefg\n

:execute '!echo' substitute(@m, '\n', '\\n', 'g')
a
ab
abc
abce
abcef
abcefg


Press ENTER or type command to continue

补充说明:

  • 当使用处理转义字符的双引号时,与单引号字符串相反,我们将不得不再次将转义数量加倍:substitute(@m, '\n', "\\\\n", 'g').
  • 如果你想去掉尾随的换行符,使用trim(@)

我想你在找 shellescape():

:execute "!echo " . shellescape(@@, 1)

使用非零参数作为第二个参数,<NL> 字符也被转义。

如需更多帮助,请参阅:

:h shellescape()