如何干净地拆分 shell 命令输出的 stdout 和 stderr 并将后者显示在 Vim 状态行中?
How to split stdout and stderr of shell command output cleanly and show the latter in Vim status line?
我使用 Vim 作为仪表板,monitor/update 许多 table 具有各种外部(过滤)命令,运行 来自宏。它们工作得非常好,除了错误输出(还不完美,虽然我已经解决了这个消息集成的 80%。请参阅 p.s。有关此类应用程序的故事)。
例如下面的table是针对"I love coffee"游戏的:
TYPE | STAT | NAME | GOAL | DONE | TODO | S1 | S2 | S3
drink | . | Latte | 250 | 178 | 72 | . | . | .
drink | . | Cocoa | 99 | 46 | 50 | . | 3 | .
drink | . | Mocha | 250 | 190 | 40 | 12 | 8 | .
drink | . | Espresso | 30 | 0 | 20 | 10 | . | .
drink | . | Iced Latte | 54 | 8 | 37 | . | . | 9
cake | . | Egg Tart | 25 | 15 | 4 | 6 | . | .
cake | . | Tiramisu | 36 | 6 | 20 | 4 | 6 | .
cake | . | Brûlée | 11 | 0 | 9 | . | 2 | .
cake | v | Pudding | 20 | 20 | 0 | . | . | .
我在寄存器 s 中有以下宏:
'oV}!order-update.pl 2>/tmp/vim.err ^M:if getfsize('/tmp/vim.err')>0|echo join(readfile('/tmp/vim.err'),"\|")|endif ^M'o
(^M
是字符ctrl-M
),
当我触及 Store1/2/3 中的数量时,这有助于更新 DONE
和 TODO
列。 (如果完成,将进行 v
检查并将线向下移动到历史区域的顶部。)
当S1
/S2
/S3
的数字有问题时,重定向2>
会从stdout输出溢出stderr输出并保存在vim.err
文件。 (不要弄乱 table)
if...endif
块将返回错误输出并将其回显到状态行。当我将 9
放入 S3
时,它将打印 Store3 drink: 9 > 8 max
。 (但是 S3
最多可以装 8 杯饮料。)
我的问题是最后一个 ex 命令行:
:if getfsize('/tmp/vim.err')>0|echo join(readfile('/tmp/vim.err'),"\|")|endif
如果没有错误发生,将保留在状态行中。
我该如何改进它?
p.s。
此类应用程序的故事
上面的(简化的)示例演示了我如何使用 Vim 作为快速电子表格,因为我每天都会更新许多 table。好处是 - 我不必离开我最喜欢的 Vim.
通过一些语法高亮显示,Vim 可以以我最喜欢的方式呈现那些 table。 (取决于这些值)
使用相关过滤器,每个 table 都可以根据值的依赖关系正确更新。
多年来,我为各种项目开发了许多 syntax/filter 对。最近我意识到我还没有将过滤器的错误消息集成到 Vim 的环境中。此类消息将随机合并到正常输出中并弄乱table。 (使用 Vim 的默认设置 shellredir=">%s 2>$1")
我的目的是收集过滤器的 stderr 消息并将它们放入 Vim 的状态行。
我的实验取得了一些成果:
宏中指定的“2>vim.err”可以否决默认的“2>&1”,将stderr拆分到临时文件中。
readfile() 函数非常适合读取整个文件。
对于检测到的小错误,过滤器最好不要以非零值退出。这样的值将使 Vim 做更多的事情并引发 "Hit-enter" 提示。
在状态行中顺利地调整 stderr 消息是我的最后一块拼图。
将宏保存在寄存器中对于在单个编辑会话中完成的重复性任务很好。对于您更经常需要的东西,我会定义一个适当的映射。对于 Vim,"upgrade" 很简单:宏内容成为 :map
命令的右侧(|
成为 <Bar>
和 ^M
成为 <CR>
),你将其放入 ~/.vimrc
:
:nnoremap <Leader>s 'oV}!order-update.pl ...
如果你使用:nnoremap <silent>
,键将不会被打印出来,你应该只会看到:echo
的结果。
要实用地修复您的宏,只需在末尾添加一个 else|echo|endif
。
我认为 "else|echo" 不是始终清除状态行的好解决方案。它很丑而且没有针对您的宏进行优化。
从过滤程序的标准错误中查看您的 tmp 文件 vim.err 的内容。如果过滤器没有发现任何奇怪的东西,它应该不包含任何内容。它的空内容将帮助您清除 OK 状态下的状态行。我会将您的宏重写为(更简单和更清晰):
'oV}!order-update.pl 2>/tmp/vim.err ^M:echo join(readfile('/tmp/vim.err'),"\|") ^M'o
另外,我不同意Karkat先生的评论:"Macro kept in a register is only good for a single editing session"。事实上,宏保存在 .viminfo 中并且在会话之间可用。它们永远不会消失,除非你给它们分配空值。在我看来,宏与映射一样强大。而且,宏比映射更方便(更容易创建和维护)。至少你可以避免逃避映射的噩梦。只有当它足够成熟并且在全球范围内有用时,我才会将宏转录为映射。
我使用 Vim 作为仪表板,monitor/update 许多 table 具有各种外部(过滤)命令,运行 来自宏。它们工作得非常好,除了错误输出(还不完美,虽然我已经解决了这个消息集成的 80%。请参阅 p.s。有关此类应用程序的故事)。
例如下面的table是针对"I love coffee"游戏的:
TYPE | STAT | NAME | GOAL | DONE | TODO | S1 | S2 | S3
drink | . | Latte | 250 | 178 | 72 | . | . | .
drink | . | Cocoa | 99 | 46 | 50 | . | 3 | .
drink | . | Mocha | 250 | 190 | 40 | 12 | 8 | .
drink | . | Espresso | 30 | 0 | 20 | 10 | . | .
drink | . | Iced Latte | 54 | 8 | 37 | . | . | 9
cake | . | Egg Tart | 25 | 15 | 4 | 6 | . | .
cake | . | Tiramisu | 36 | 6 | 20 | 4 | 6 | .
cake | . | Brûlée | 11 | 0 | 9 | . | 2 | .
cake | v | Pudding | 20 | 20 | 0 | . | . | .
我在寄存器 s 中有以下宏:
'oV}!order-update.pl 2>/tmp/vim.err ^M:if getfsize('/tmp/vim.err')>0|echo join(readfile('/tmp/vim.err'),"\|")|endif ^M'o
(^M
是字符ctrl-M
),
当我触及 Store1/2/3 中的数量时,这有助于更新 DONE
和 TODO
列。 (如果完成,将进行 v
检查并将线向下移动到历史区域的顶部。)
当S1
/S2
/S3
的数字有问题时,重定向2>
会从stdout输出溢出stderr输出并保存在vim.err
文件。 (不要弄乱 table)
if...endif
块将返回错误输出并将其回显到状态行。当我将 9
放入 S3
时,它将打印 Store3 drink: 9 > 8 max
。 (但是 S3
最多可以装 8 杯饮料。)
我的问题是最后一个 ex 命令行:
:if getfsize('/tmp/vim.err')>0|echo join(readfile('/tmp/vim.err'),"\|")|endif
如果没有错误发生,将保留在状态行中。
我该如何改进它?
p.s。
此类应用程序的故事
上面的(简化的)示例演示了我如何使用 Vim 作为快速电子表格,因为我每天都会更新许多 table。好处是 - 我不必离开我最喜欢的 Vim.
通过一些语法高亮显示,Vim 可以以我最喜欢的方式呈现那些 table。 (取决于这些值)
使用相关过滤器,每个 table 都可以根据值的依赖关系正确更新。
多年来,我为各种项目开发了许多 syntax/filter 对。最近我意识到我还没有将过滤器的错误消息集成到 Vim 的环境中。此类消息将随机合并到正常输出中并弄乱table。 (使用 Vim 的默认设置 shellredir=">%s 2>$1")
我的目的是收集过滤器的 stderr 消息并将它们放入 Vim 的状态行。
我的实验取得了一些成果:
宏中指定的“2>vim.err”可以否决默认的“2>&1”,将stderr拆分到临时文件中。
readfile() 函数非常适合读取整个文件。
对于检测到的小错误,过滤器最好不要以非零值退出。这样的值将使 Vim 做更多的事情并引发 "Hit-enter" 提示。
在状态行中顺利地调整 stderr 消息是我的最后一块拼图。
将宏保存在寄存器中对于在单个编辑会话中完成的重复性任务很好。对于您更经常需要的东西,我会定义一个适当的映射。对于 Vim,"upgrade" 很简单:宏内容成为 :map
命令的右侧(|
成为 <Bar>
和 ^M
成为 <CR>
),你将其放入 ~/.vimrc
:
:nnoremap <Leader>s 'oV}!order-update.pl ...
如果你使用:nnoremap <silent>
,键将不会被打印出来,你应该只会看到:echo
的结果。
要实用地修复您的宏,只需在末尾添加一个 else|echo|endif
。
我认为 "else|echo" 不是始终清除状态行的好解决方案。它很丑而且没有针对您的宏进行优化。
从过滤程序的标准错误中查看您的 tmp 文件 vim.err 的内容。如果过滤器没有发现任何奇怪的东西,它应该不包含任何内容。它的空内容将帮助您清除 OK 状态下的状态行。我会将您的宏重写为(更简单和更清晰):
'oV}!order-update.pl 2>/tmp/vim.err ^M:echo join(readfile('/tmp/vim.err'),"\|") ^M'o
另外,我不同意Karkat先生的评论:"Macro kept in a register is only good for a single editing session"。事实上,宏保存在 .viminfo 中并且在会话之间可用。它们永远不会消失,除非你给它们分配空值。在我看来,宏与映射一样强大。而且,宏比映射更方便(更容易创建和维护)。至少你可以避免逃避映射的噩梦。只有当它足够成熟并且在全球范围内有用时,我才会将宏转录为映射。