21

我正在玩 i/o shell 重定向。我尝试过的命令(在 bash 中):

ls -al *.xyz 2>&1 1> files.lst

ls -al *.xyz 1> files.lst 2>&1

当前文件夹中没有任何*.xyz文件。

这些命令给了我不同的结果。第一个命令ls: *.xyz: No such file or directory在屏幕上显示一条错误消息。但是第二个将此错误消息打印到文件中。为什么第一个命令无法将错误输出写入文件?

4

5 回答 5

42

Bash 手册有一个清晰的示例(类似于您的示例),以表明顺序很重要并解释了差异。这是摘录的相关部分(强调我的):

请注意,重定向的顺序很重要。例如,命令

ls >目录2>&1

将标准输出(文件描述符 1)和标准错误(文件描述符 2)都指向文件dirlist,而命令

ls 2>&1 >目录

仅将标准输出定向到文件dirlist,因为在标准输出重定向到dirlist之前,标准错误是标准输出的副本。

这篇文章从 POSIX 的角度解释了它。

由于关键差异而发生混乱。>重定向不是通过使左操作数 ( stderr) 指向右操作数 ( stdout) 而是通过复制右操作数并将其分配给左侧。从概念上讲,通过复制而不是通过引用分配。

因此,从左到右读取这就是 Bash 的解释方式:ls > dirlist 2>&1意味着重定向stdout到文件dirlist,然后重定向stderr到当前的任何stdout内容(这已经是文件dirlist)。但是,ls 2>&1 > dirlist将重定向stderr到当前的任何stdout内容(即屏幕/终端),然后重定向stdoutdirlist.

于 2014-08-12T08:28:27.650 回答
18

重定向是:

  • 从左到右处理。
  • 反复解释:
    • 较早的重定向可能会影响以后重定向:
      • 如果较早的重定向已重定向给定的流(由文件描述符编号标识,例如1stdout(默认值)和2stderr),则针对该流的后续重定向将引用已重定向的版本。
    • 反之亦然- 稍后的重定向对早期重定向的目标没有追溯影响:
      • 1例如,如果您在较早的重定向中将文件描述符指定为目标,则1意味着当时被锁定,即使1稍后重定向也是如此。
  • 但是请注意,在所有重定向到位之前实际上不会发送输出,并且在命令执行开始之前创建或截断任何重定向目标输出文件(这就是您无法读取并将输出重定向到的原因使用单个命令的相同文件)。

应用于问题中的示例:

  • >file 2>&1

    • >file 首先将stdout(文件描述符1,不>以文件描述符编号作为前缀暗示)重定向到输出文件file
    • 2>&1 然后将 stderr ( 2) 重定向到已经重定向的stdout ( 1)。
    • 最终结果是两个原始流都以file.
  • 2>&1 >file

    • 2>&1首先将 stderr 重定向到当时的原始标准输出;由于文件描述符2不参与进一步的重定向,因此 stderr 输出将转到当时定义的任何标准输出-原始标准输出,因为这是第一次重定向。
      • 从技术上讲,原始的 stdout 文件描述符是duplicated,而该副本就是 stderr 所指的内容,这就解释了为什么它不受以后的 stdout 重定向的影响。
    • >file然后将原始标准输出重定向到file- 但这对已经锁定的标准错误重定向不再有影响。
    • 最终效果是,仅file
于 2015-12-17T04:08:23.930 回答
14

这个错误:

ls: *.xyz: No such file or directory

正在stderrls二进制写入。

但是在这个命令中:

ls -al *.xyz 2>&1 1> files.lst

您首先重定向 stderrstdout默认情况下转到tty(终端)

然后你重定向stdout到一个文件files.lst,但是请记住,stderr 不会重定向到文件,因为你必须在stderr重定向stdout之前重定向 。在这种情况下,您仍然会被写入。stdoutfilestderrtty

但是在第二种情况下,您更改重定向的顺序(首先stdoutfile然后stderrstdout),并且正确地重定向stderrfile也被stdout.

于 2013-07-31T16:13:57.687 回答
2

因为顺序确实很重要。在第一种情况下,您首先将 stderr (2) 重定向到 stdout (1)。然后将 (1) 重定向到一个文件。但是 stderr (2) 仍然指向运行命令的 shell 的标准输出。在这种情况下,将 (1) 指向文件不会更改 (2) 指向的输出设备,因此它仍会转到终端。

在第二种情况下,您将 stdout (1) 重定向到文件。然后你将stderr(2)指向同一个地方1被指向,也就是文件,所以错误信息转到文件。

于 2013-07-31T16:16:04.813 回答
1

重定向从左到右处理

他们是一样的:

  • my_cmd 1>a_file
  • my_cmd >a_file

我记住整件事的方法

让我们想象我们正在玩一个游戏。有一座有 2 个破损部分的桥。

  1. 如果我们先放置一个名为的方块2>&1来修复第一个破碎的部分,那么命名的球stderrr可以到达名为的地方stdout,但是由于第二部分仍然破碎, stderrr会掉到一条名为的河流tty(到你的屏幕上)。然后我们放置一个方块命名1>a_file修复第二个破损部分,命名的球stdout可以到达命名的地方a_file

  2. 如果我们先放置一个名为1>a_file修复第二个破损部分的块,然后用修复第一个破损部分2>&1,球stderrr就不会掉到河里。tty 在此处输入图像描述

于 2022-02-25T02:47:08.817 回答