IO 重定向和 head 命令

voi*_*hos 11 shell io-redirection

.hgignore今天试图从 Cygwin bash shell快速编辑一个文件,但我添加了一行错误。我不确定这是否是最好的方法,但我很快想到使用head -1 .hgignore删除有问题的行(我以前在文件中只有一行)。果然,执行时它给出了第一行作为唯一的输出。

但是当我尝试重定向输出并使用 重写文件时head -1 .hgignore > .hgignore,该文件为空。为什么会发生这种情况?如果我尝试附加,head -1 .hgignore >> .hgignore,它会正确附加,但这显然不是想要的结果。为什么在这种情况下截断重定向不起作用?

Cal*_*leb 13

我认为布鲁斯用 shell 管道回答了这里发生的事情

我最喜欢的小工具之一是sponge来自moreutils的命令。它通过在打开目标输出文件并写入数据之前“吸收”所有可用输入来解决这个问题。它允许您完全按照您的预期编写管道:

$ head -1 .hgignore | sponge .hgignore
Run Code Online (Sandbox Code Playgroud)

穷人的解决方案是将输出通过管道传输到临时文件,然后在管道完成后(例如您运行的下一个命令)将临时文件移回原始文件位置。

$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}
Run Code Online (Sandbox Code Playgroud)

  • @voithos Yes 管道中的命令和所有涉及的输入/输出通道都以相反的顺序启动,因此当第一个开始提供数据时,管道已准备好接收数据。我怀疑您的测试存在缺陷,因为您可能使用了太小的数据块,并且在您需要之前它已将整个内容缓存在读取缓冲区中。`tee` 程序会截断你的文件,它没有设置双缓冲。 (2认同)

Bru*_*ger 11

当 shell 获得如下命令行时:command > file.outshell 本身打开(并可能创建)名为file.out. shell 将文件描述符 0 设置为它从打开中获得的文件文件描述符。这就是 I/O 重定向的工作原理:每个进程都知道文件描述符 0、1 和 2。

难点在于如何打开file.out. 大多数情况下,您希望file.out在偏移量 0(即截断)处打开写入,这就是 shell 为您所做的。它截断了 .hgignore,将其打开以进行写入,将文件描述符复制为 0,然后执行 exec'ed head。即时文件破坏。

在 bash shell 中,您可以执行 aset noclobber来更改此行为。