命令重定向到多个文件:command >file1 >file2

命令重定向到多个文件:command >file1 >file2

我有这个命令:

cat somefile >file1 >file2

执行此命令后,我不明白为什么file1其中没有任何内容。它应该有第一个文件 ( ) 的输出somefile,但其中什么也没有。

你能向我解释一下为什么它不复制或写入我的输出吗somefile? (file2包含我的输出,但file1不包含任何内容)

答案1

我认为您认为 shell 重定向的工作方式与实际工作方式之间存在差异。

除了 in zshtee当输出被重定向多次时,它会在所看到的后面实现类似的行为),您不能多次重定向 shell 的输出并期望它被重定向到您指定的所有位置。相反,它只会被重定向到最后一个位置,在您的情况下是file2. Chaos 的答案对 I/O 重定向的工作原理提供了很好的解释。

你真正想做的是:

$ cat example.txt | tee file1 > file2

tee是一个从标准输入读取并写入多个文件描述符的程序。其中之一是总是标准输出。因此,我们使用tee将输出写入file1,然后将其标准输出重定向到file2.

另外,根据评论中的建议,这是完成您正在寻找的事情的更好方法:

$ tee file1 < example.txt > file2

这种方法的优点是它可以重定向stdin而不是尝试通过管道读取。这意味着 shell 现在需要少生成一个进程。它还消除了所谓的“猫的无用使用”。通过放置输出重定向输入重定向,如果输入文件无法打开,我们可以避免输出文件被破坏。

答案2

你所做的,被称为I/O 重定向>file将标准输出 (stdout) 重定向到给定的file.在你的情况下,你做了两次。 shell 不会多次处理同一输出的重定向。

在这种情况下:

cat somefile >file1 >file2

shell 在cat somefile执行命令 ( ) 之前处理重定向。这意味着>文件将截断为零长度,因为您覆盖了文件内容。该文件必须为空,shell 才能执行该命令。这是通过两个>重定向完成的。

现在,第二个 ( >file2) 会覆盖第一个 ( >file1),因为 shell 按出现顺序处理重定向。因此,最后一项是有效使用的一项。因此, 的输出cat somefile将被重定向file2并被file1截断为零长度。


tee将标准输出重定向到多个进程/文件可以这样完成:

cat somefile | tee file1 file2 file3 fileX

这会将内容打印到标准输出到作为参数给出的所有文件。

答案3

zsh多重选项设置(默认情况下),您可以使用:

cat somefile >file1 >file2

在这种情况下,执行类似于幕后的zsh操作。tee甚至:

<somefile >file1 >file2

作为 的默认值$NULLCMD,当有没有命令的重定向时运行的命令恰好是cat

答案4

cat somefile >file1 >file2

如果没有重定向,cat somefile将从 shell 继承 stdin。通常 shell 的 stdin 没有关闭,它已经指向某个文件。终端也是一个文件。当您在标准输出为终端的交互式 shell 中运行时cat somefile, 的输出cat将转到终端。一般来说,shell 的标准输出可能是其他不相关的东西,cat无论如何都会继承它。

cat somefile >file1的作用是使外壳:

  • 尝试打开file1以进行写入(如果文件尚不存在,则会创建文件)并将其截断为零大小(如果可能);这发生在cat开始之前;
  • 设置file1为未来的标准输出cat,因此cat将使用file1 代替如果没有重定向它会使用什么(您不希望cat somefile >file1也写入您的终端,对吧?)。

重定向重定向。:) 当前方向是“到终端”,新方向是“到file1”。采取新方向代替当前方向和新方向成为当前方向。

shell 从左到右解析重定向。如果是cat somefile >file1 >file2外壳,首先>file1按上述方式进行处理。然后它处理>file2 以同样的方式:它打开并截断文件,并file2为将来设置“to”cat 代替当前方向此时已经是“to file1”。这种方式“to file2”取代了“to file1”并成为当前状态,就像file1刚才“to”取代了“to theterminal”一样。

您可以添加更多>fileN重定向,每个重定向都将按照所描述的方式进行处理。假设每个人都成功,那么最后一个人就会获胜。在你的情况下>file2获胜。

处理完所有重定向后,cat开始。您catfile2其视为标准输出,但它甚至不知道file1以任何方式参与其中。的截断file1是一个“副作用”,只是因为>file1已经被shell解析了,与 无关cat

您可以使用此机制来创建/截断一个或多个文件:: >file1 >file2 …将尝试截断文件。:是一个无操作,它甚至不使用它的标准输出。当 shell 在启动之前处理重定向时,会发生创建和截断:


这就是输出重定向在sh兼容 shell 中的工作方式。中的 MULTIOS 选项zsh(参见这个另一个答案)不同:第一次重定向替换旧方向(例如终端),而连续重定向添加方向。它是如何在幕后发生的,我不会详细说明。我只是想指出,您观察到的行为来自于每个都被处理sh(或在兼容的外壳中)的事实>fileN独立地, 相继;但在zsh有一种模式下,它将多个输出重定向更像一个单元。

相关内容