太长了;博士

太长了;博士

这让 vim 疯狂:

$strace -o >(vim -; stty sane) file.out; stty sane

我已经输入了stty sane已处理的替换以及下一个命令,但它们都没有完成其工作。一旦我将 strace 命令通过管道传输到 vim,那么 vim 就不再表现正常(我知道 vim 只能接受stdin并且 strace 向 提供输出stderr,但那么该-o标志是做什么用的?)有什么帮助吗?

答案1

太长了;博士

strace -o '|vim -' file.out

关于-o

-o存在是为了提供与 stdout 或 stderr 不同的附加输出通道。没有-o strace打印到其 stderr,这也是命令的 stderr(file.out在您的情况下)。能够将两个流分开是件好事,-o使这成为可能。


问题

你的方法有缺陷,与你想象的不同,stty sane无济于事。让我重复一下命令:

strace -o >(vim -; stty sane) file.out; stty sane

它有两个普遍的问题:

  1. 启用作业控制后,就会出现一个概念前台进程组。在任何时候,终端都会识别出前台的一组。不在前台进程组中的进程正式处于后台。

后台进程无法从其控制终端读取数据;SIGTTIN如果它尝试,它就会收到。该信号将阻止它,除非进程忽略它或以不同方式处理。

后台进程可以写入其控制终端,但如果它尝试并stty tostop启用,则该进程将接收SIGTTOU.该信号将阻止它,除非进程忽略它或以不同方式处理。如果不停止,尽管tostop有信号,该进程仍能够写入终端。

上述机制可以防止后台进程窃取终端的输入,但仍然保持它们与终端的连接,因此可以将它们带到前台并进行操作。然后从终端读取。这对于启动进程的终端很有用。与其他终端可能的交互与处于前台还是后台无关,无论如何其他终端都是“外部”的;因此,只要进程具有足够的权限,就可以从不是其控制终端的终端读取或写入。

在您的情况下,最初前台进程组是与 shell 关联的进程组;然后用strace;然后与stty(外面的>());最后再次使用外壳。

在 Bash 内部的进程>()被分配给处理>().这意味着只有在(外部的)完成并且shell 的进程组被置于前台vim之后,您才能从终端读取数据。这就带来了第二个问题。stracestty>()

  1. vim最终能够从终端读取时,shell 也会尝试读取。比较这两个:
  • strace -o >(vim -) true

    移动光标。一些输入将转到vim,一些输入将转到 shell。他们都在前台。

  • strace -o >(vim -) true; sleep 1000

    尝试移动光标。现在不同了,因为sleep它在前台。sleepCtrl+终止C,行为将会改变。

在任何情况下,您都可以通过vim从另一个控制台杀死来恢复(killall vim除非有另一个控制台vim并且您想保留它)。

这就是你观察到的疯狂。罪魁祸首超出了stty sanereset或的范围tput reset


琐事

  1. 以下命令会产生不同的疯狂:

     <<<"foo" tee >(vim -)
     <<<"foo" tee > >(vim -)
    

第一种情况>()由主 shell 处理并vim放置在 shell 的进程组中。一旦退出就可以从终端读取数据tee(尽管 shell 会干扰);我们之前已经见过这个了strace

第二种情况>()由处理 的 shell 处理>。它是一个将成为 (exec to) 的子 shell tee。实际上vim被放置在一个进程组中tee。只要tee停留在前台,它就可以从终端读取数据。

因为tee几乎立即退出,所以第一个vim几乎立即能够从终端读取,而第二个vim几乎立即无法读取。

  1. 我的测试表明,>(vim -)Zsh 位于vim另一个进程组中,而不是处理>().那么vim永远不能在前台。似乎还有其他差异,但我不会详细说明。

通用解决方案(不依赖于strace

  • 如果禁用作业控制(使用set +m或通过在子 shell 中运行代码),则所有新进程都将属于终端视为前台的组。如果您延迟返回 shell,则 shell 不会通过从终端读取数据来干扰。尝试这个:

      (strace -o >(vim -) file.out; sleep 99999)
    

退出后使用Ctrl+C终止。如果您点击此组合,则不会受到影响,因为像 一样配置终端。sleepvimvimsleepvimstty -isig

这个解决方案并不是很优雅。我将其放在这里是因为它显示了禁用作业控制和不允许 shell 读取输入会如何影响事物。

  • 或者,您需要启动并保持vim在前台。不使用>(vim -)。使用vim …… | vim -.

最直接的方法是创建一个常规文件(在您的情况下strace -o somefile file.out)并稍后打开它(vim somefile)。


解决方案具体针对strace

避免创建文件并使用vim <(strace …)or 的解决方案strace … | vim -是可能的。我想如果您足够聪明(并且有/proc?),那么您可以操纵文件描述符并通过管道传输-o到标准输出,而无需与原始标准输出合并。

正确的事情然而是使用strace提供的-o

-o filename
--output=filename

将跟踪输出写入文件filename而不是 stderr。 […]如果参数以|or开头!,则参数的其余部分将被视为命令,并且所有输出都通过管道传输到它。这可以方便地将调试输出传送到程序,而不影响已执行程序的重定向。 […]

来源,强调我的)

你的命令变成:

strace -o '|vim -' file.out

注意|必须加引号或转义,否则 shell 将尝试构建管道。另一种选择是!,在某些 shell 中需要受到保护以及。

straceshshvim。上述问题就解决了。分别:

  1. 这三个进程属于同一个进程组。如果strace位于前台,则 也位于前台vim

  2. 交互式(外部)shell 仅在退出后尝试从终​​端strace读取。shvim

相关内容