我有以下简单命令:
$ echo <(vipe)
我希望它打开一个 vim 缓冲区,我可以对其进行编辑,然后当我完成后,回显分配用于保存 vim 缓冲区内容的临时文件的名称。
相反,vim 缓冲区的行为非常奇怪,不响应某些按键,最终 vim 完全崩溃。
我的哪个假设是错误的?
答案1
首先,让我们看看在终端中看到的内容:
$ echo <(vim)
/dev/fd/63
$ Vim: Warning: Output is not to a terminal
请注意,您会立即收到提示,而无需等待编辑器终止。进程替换不会等待命令完成,它会在命令和 shell 之间创建一个管道。该管道的名称被传递给进程替换作为其参数的命令,此处echo
打印出该名称并立即返回,之后 bash 关闭该管道。
Vim 仍在运行,其标准输入和标准错误连接到终端,但未连接其标准输出。因此,Vim 正在获取输入并发出一些错误消息,但其大部分显示都转到标准输出,这是一个损坏的管道。
bash 和 vim 都从终端读取。这会导致您的击键在一定程度上随机地发送给其中一个或另一个。这种情况通常不会发生,因为后台进程是禁止从终端读取— 如果他们尝试这样做,那么他们会收到 SIGTTIN 信号,如果他们忽略该信号,那么他们的read
调用将返回错误。但在这种情况下,vim
作为前台进程组的一部分执行,因为进程替换不会创建新的进程组,因此它可以从终端读取并捕获一些击键。
在某个时刻,Vim 决定再也无法忍受并退出。我不知道是什么让它做出这样的决定。
进程替换不会创建临时文件,而是创建管道,因此您的方法没有意义。兹什有一个进程替换结构确实创建了一个临时文件 ( =(somecommand)
),但这也不起作用:您可以运行echo =(vipe </dev/null)
,这将打印出临时文件的名称,该文件在打印时刚刚被删除。
要做你想做的事,你需要自己处理临时文件的删除。我不认为有任何 shell 结构可以帮助你。调用mktemp
创建临时文件,然后按普通方式编辑即可。
tmpfile=$(mktemp)
"${VISUAL:-"${EDITOR:-vi}"}" "$tmpfile"
echo "$tmpfile"
…
rm "$tmpfile"