Shell重定向i / o命令

时间:2013-07-31 15:58:39

标签: bash shell stdout stderr io-redirection

我正在玩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 个答案:

答案 0 :(得分:31)

Bash manual有一个明显的例子(与你的类似),以表明订单很重要,也解释了差异。这里摘录了相关部分(强调我的):

  

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

     

ls> dirlist 2>& 1

     

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

     

ls 2>& 1> dirlist

     

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

This post从POSIX观点解释。

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

因此,从左到右阅读Bash解释了这一点:ls > dirlist 2>&1表示将stdout重定向到文件dirlist,然后重定向stderr到目前的任何stdout(已经是文件dirlist)。但是,ls 2>&1 > dirlist会将stderr重定向到当前stdout(屏幕/终端),然后将stdout重定向到dirlist

答案 1 :(得分:17)

重定向是:

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

应用于问题中的示例:

  • 1

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

    • 2>&1 >file首先将stderr重定向到 then-original 标准输出;由于文件描述符2>&1不参与进一步的重定向,因此stderr输出将转到那个被定义为的stdout - 即,原始的标准输出,给定这是第一次重定向。
      • 从技术上讲,原始的stdout文件描述符是重复的,并且该副本是stderr引用的内容,这解释了为什么它不会受到后来的stdout重定向的影响。
    • 2然后将原始标准输出重定向到>file - 但这对已经锁定的stderr重定向没有任何影响。
    • 净效应是只在file中捕获了直接发送到stdout的输出,而发送到stderr的输出则输出到(原始的,未重定向的)stdout。

答案 2 :(得分:12)

此错误:

ls: *.xyz: No such file or directory

stderr二进制文件写在ls上。

但是在这个命令中:

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

您首先将 stderr重定向到stdout,默认情况下转到tty(终端)

然后您将stdout重定向到文件files.lst,但请记住stderr未重定向到文件,因为您有stderrstdout重定向 stdoutfile重定向之前。在这种情况下,stderr仍会写入tty

但是在第二种情况下,您可以更改重定向的顺序(首先stdoutfile,然后stderr更改为stdout)并正确地将stderr重定向到file也使用了stdout

答案 3 :(得分:2)

因为订单很重要。 在第一种情况下,首先将stderr(2)重定向到stdout(1)。 然后重定向(1)到文件。但是stderr(2)仍然指向运行命令的shell的stdout。在这种情况下将(1)指向文件不会改变(2)所针对的输出设备,因此它仍然会转到终端。

在第二种情况下,将stdout(1)重定向到文件。然后你将stderr(2)指向相同的位置1,这是文件,因此错误消息将转到文件。