首页 文章

在shell中,“2>&1”是什么意思?

提问于
浏览
1842

在Unix shell中,如果我想将 stderrstdout 组合到 stdout 流中以进行进一步操作,我可以在命令末尾附加以下内容:

2>&1

所以,如果我想在 g++ 的输出上使用 head ,我可以这样做:

g++ lots_of_errors 2>&1 | head

所以我只能看到前几个错误 .

我总是很难记住这一点,而且我不得不去查找它,主要是因为我不完全理解这个特殊技巧的语法 .

有人可以打破这个并按字符解释 2>&1 的意思吗?

15 回答

  • 10
    echo test > afile.txt
    

    将stdout重定向到 afile.txt . 这和做的一样

    echo test 1> afile.txt
    

    要重定向stderr,您可以:

    echo test 2> afile.txt
    

    >& 是将流重定向到另一个文件描述符的语法 - 0是stdin,1是stdout,2是stderr .

    您可以通过执行以下操作将stdout重定向到stderr:

    echo test 1>&2 # or echo test >&2
    

    或相反亦然:

    echo test 2>&1
    

    所以,简而言之...... 2> 将stderr重定向到(未指定的)文件,追加 &1 将stderr重定向到stdout .

  • 2050

    数字指的是文件描述符(fd) .

    • 零是 stdin

    • 一个是 stdout

    • 两个是 stderr

    2>&1 将fd 2重定向到1 .

    如果程序使用它,这适用于任意数量的文件描述符 .

    如果忘了它们,你可以看 /usr/include/unistd.h

    /* Standard file descriptors.  */
    #define STDIN_FILENO    0   /* Standard input.  */
    #define STDOUT_FILENO   1   /* Standard output.  */
    #define STDERR_FILENO   2   /* Standard error output.  */
    

    这就是说我编写了使用非标准文件描述符进行自定义日志记录的C工具,因此除非将其重定向到文件或其他内容,否则不会看到它 .

  • 51

    该构造将标准错误流( stderr )发送到标准输出的当前位置( stdout ) - 这个货币问题似乎被其他答案忽略了 .

    您可以使用此方法将任何输出句柄重定向到另一个输出句柄,但它最常用于将 stdoutstderr 流引导到单个流中进行处理 .

    一些例子是:

    # Look for ERROR string in both stdout and stderr.
    foo 2>&1 | grep ERROR
    
    # Run the less pager without stderr screwing up the output.
    foo 2>&1 | less
    
    # Send stdout/err to file (with append) and terminal.
    foo 2>&1 |tee /dev/tty >>outfile
    
    # Send stderr to normal location and stdout to file.
    foo >outfile1 2>&1 >outfile2
    

    请注意,最后一个不会将 stderr 指向 outfile2 - 它会将其重定向到遇到参数时的 stdoutoutfile1 ),然后将 stdout 重定向到 outfile2 .

    这允许一些非常复杂的技巧 .

  • 15

    回答你的问题:它需要任何错误输出(通常发送到stderr)并将其写入标准输出(stdout) .

    当您需要对所有输出进行分页时,这有助于例如“更多” . 有些程序喜欢将使用信息打印到stderr中 .

    帮助你记住

    • 1 =标准输出(程序打印正常输出)

    • 2 =标准错误(程序打印错误)

    “2>&1”只是将发送到stderr的所有内容指向stdout .

    我还建议阅读this post on error redirecting,其中详细介绍了该主题 .

  • 4

    重定向输入重定向输入导致打开名称由word扩展产生的文件以便在文件描述符n上读取,或者如果未指定n则打开标准输入(文件描述符0) . 重定向输入的一般格式是:[n] <word
    重定向输出重定向输出会导致名称由word扩展产生的文件在文件描述符n上打开,或者如果未指定n则打开标准输出(文件描述符1) . 如果文件不存在则创建;如果确实存在则将其截断为零大小 . 重定向输出的一般格式是:[n]>字
    移动文件描述符重定向操作符,[n] <&digit-
    如果未指定n,则将文件描述符数字移动到文件描述符n或标准输入(文件描述符0) . 数字在复制到n后关闭 . 同样,重定向运算符[n]>&digit-
    如果未指定n,则将文件描述符数字移动到文件描述符n或标准输出(文件描述符1) .

    参考:

    man bash
    

    键入 /^REDIRECT 以找到 redirection 部分,并了解更多...

    在线版本在这里:3.6 Redirections

    PS:

    很多时候, man 是学习Linux的强大工具 .

  • 72

    2>&1 是POSIX shell构造 . 以下是按令牌分类的令牌:


    2 :“ Standard error ”输出文件描述符 .

    >&Duplicate an Output File Descriptor运算符(Output Redirection运算符 > 的变体) . 给定 [x]>&[y]x 表示的文件描述符将成为输出文件描述符 y 的副本 .

    1Standard output ”输出文件描述符 .

    表达式 2>&1 将文件描述符 1 复制到位置 2 ,因此在执行环境中写入 2 ("standard error")的任何输出都将转到最初由 1 ("standard output")描述的同一文件 .


    进一步说明:

    File Descriptor:"A per-process unique, non-negative integer used to identify an open file for the purpose of file access."

    Standard output/error :请参阅shell文档的Redirection部分中的以下注释:

    打开文件由以零开头的十进制数表示 . 最大可能的值是实现定义的;但是,所有实现都应支持至少0到9(包括0和9),以供应用程序使用 . 这些数字称为“文件描述符” . 值0,1和2具有特殊含义和常规用途,并且由某些重定向操作暗示;它们分别称为标准输入,标准输出和标准误差 . 程序通常从标准输入中获取输入,并在标准输出上写入输出 . 错误消息通常写在标准错误上 . 重定向运算符可以在一个或多个数字前面(不允许插入字符)来指定文件描述符号 .

  • 0

    这就像将错误传递给stdout或终端一样 .

    也就是说, cmd 不是命令:

    $cmd 2>filename
    cat filename
    
    command not found
    

    错误发送到文件,如下所示:

    2>&1
    

    标准错误发送到终端 .

  • 508

    关于重定向的一些技巧

    关于此的一些语法特殊性可能具有重要的行为 . 有一些关于重定向的小样本, STDERRSTDOUT 和参数 ordering .

    1 - 覆盖或追加?

    符号 > 表示重定向 .

    • > 表示发送到整个已完成的文件,如果存在则覆盖目标(稍后请参阅#71586_ bash功能#3) .

    • >> 如果存在,则另外发送将附加到目标 .

    在任何情况下,如果文件不存在,将创建该文件 .

    2 - shell命令行依赖于订单!!

    为了测试它,我们需要一个简单的命令,它将在两个输出上发送一些东西:

    $ ls -ld /tmp /tnt
    ls: cannot access /tnt: No such file or directory
    drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp
    
    $ ls -ld /tmp /tnt >/dev/null
    ls: cannot access /tnt: No such file or directory
    
    $ ls -ld /tmp /tnt 2>/dev/null
    drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp
    

    (当然,期待您没有名为 /tnt 的目录;) . 好吧,我们拥有它!

    所以,让我们看看:

    $ ls -ld /tmp /tnt >/dev/null
    ls: cannot access /tnt: No such file or directory
    
    $ ls -ld /tmp /tnt >/dev/null 2>&1
    
    $ ls -ld /tmp /tnt 2>&1 >/dev/null
    ls: cannot access /tnt: No such file or directory
    

    最后一个命令行将 STDERR 转储到控制台,它似乎不是预期的行为......但......

    如果你想对一个输出,另一个或两个输出进行一些后置过滤:

    $ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
    ls: cannot access /tnt: No such file or directory
    <-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->
    
    $ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
    <-- ls: cannot access /tnt: No such file or directory --->
    <-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->
    
    $ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
    ls: cannot access /tnt: No such file or directory
    
    $ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'
    
    $ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
    <-- ls: cannot access /tnt: No such file or directory --->
    

    请注意,此段落中的最后一个命令行与上一段中的完全相同,我写的内容似乎不是预期的行为(因此,这甚至可能是预期的行为) .

    嗯,有一些关于重定向的小技巧,对于 doing different operation on both outputs

    $ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
    O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
    E: ls: cannot access /tnt: No such file or directory
    

    Nota: &9 描述符会因为 ) 9>&2 而自发发生 .

    Addendum: nota! 使用bash>4.0 )的新版本,有一个新功能和更性感的语法来执行此类操作:

    $ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
    O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
    E: ls: cannot access /tnt: No such file or directory
    

    最后对于这样的级联输出格式:

    $ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
         1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
         2  E: ls: cannot access /tnt: No such file or directory
    

    Addendum: nota! 相同的新语法,两种方式:

    $ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
         1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
         2  E: ls: cannot access /tnt: No such file or directory
    

    STDOUT 通过一个特定的过滤器, STDERR 到另一个,最后两个输出合并通过第三个命令过滤器 .

    3 - 关于noclobber选项和> |的一个词句法

    那是关于 overwriting

    set -o noclobber 指示bash到 not 覆盖任何现有文件时, >| 语法允许您通过此限制:

    $ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)
    
    $ date > $testfile ; cat $testfile
    Mon Jan  7 13:18:15 CET 2013
    
    $ date > $testfile ; cat $testfile
    Mon Jan  7 13:18:19 CET 2013
    
    $ date > $testfile ; cat $testfile
    Mon Jan  7 13:18:21 CET 2013
    

    每次都会覆盖该文件,现在好了:

    $ set -o noclobber
    
    $ date > $testfile ; cat $testfile
    bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
    Mon Jan  7 13:18:21 CET 2013
    
    $ date > $testfile ; cat $testfile
    bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
    Mon Jan  7 13:18:21 CET 2013
    

    通过 >|

    $ date >| $testfile ; cat $testfile
    Mon Jan  7 13:18:58 CET 2013
    
    $ date >| $testfile ; cat $testfile
    Mon Jan  7 13:19:01 CET 2013
    

    取消设置此选项和/或询问是否已设置 .

    $ set -o | grep noclobber
    noclobber           on
    
    $ set +o noclobber
    
    $ set -o | grep noclobber
    noclobber           off
    
    $ date > $testfile ; cat $testfile
    Mon Jan  7 13:24:27 CET 2013
    
    $ rm $testfile
    

    4 - 最后的伎俩......

    为了从给定命令重定向 both 输出,我们看到正确的语法可能是:

    $ ls -ld /tmp /tnt >/dev/null 2>&1
    

    对于这种特殊情况,有一种快捷语法: &> ...或 >&

    $ ls -ld /tmp /tnt &>/dev/null
    
    $ ls -ld /tmp /tnt >&/dev/null
    

    注意:如果 2>&1 存在, 1>&2 也是正确的语法:

    $ ls -ld /tmp /tnt 2>/dev/null 1>&2
    

    4 b-现在,我会让你考虑一下:

    $ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
    ++/bin/ls: cannot access /tnt: No such file or directory
    ++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/
    
    $ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
    /bin/ls: cannot access /tnt: No such file or directory
    drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/
    

    4 c-如果您对更多信息感兴趣

    您可以通过点击阅读精细手册:

    man -Len -Pless\ +/^REDIRECTION bash
    

    在一个bash控制台;-)

  • 271

    文件描述符1是标准输出( stdout ) .
    文件描述符2是标准错误( stderr ) .

    这是记住这个结构的一种方法(尽管它并不完全准确):首先, 2>1 可能看起来像是将 stderr 重定向到 stdout 的好方法 . 但是,它实际上将被解释为“将 stderr 重定向到名为 1 的文件” . & 表示后面是文件描述符而不是文件名 . 所以构造变成: 2>&1 .

  • 58

    2是控制台标准错误 .

    1是控制台标准输出 .

    这是标准的Unix,Windows也遵循POSIX .

    例如 . 当你跑步

    perl test.pl 2>&1
    

    标准错误被重定向到标准输出,因此您可以同时看到两个输出:

    perl test.pl > debug.log 2>&1
    

    执行后,您可以在debug.log中查看所有输出,包括错误 .

    perl test.pl 1>out.log 2>err.log
    

    然后标准输出转到out.log,标准错误转到err.log .

    我建议你试着理解这些 .

  • 13

    人们,永远记得paxdiablo关于重定向目标 current 位置的暗示......重要的是 is .

    我对 2>&1 运算符的个人助记符是这样的:

    • & 视为含义 'and''add' (该字符为ampers- and ,不是吗?)

    • 因此它变成:'重定向 2 (stderr)到 1 (标准输出)已经/当前是 add 两个流' .

    同样的助记符也适用于其他常用的重定向, 1>&2

    • 想到 & 意思是 andadd ......(你明白了&符号,是吗?)

    • 所以它变成:'重定向 1 (标准输出)到 2 (stderr)已经/当前是 add 两个流' .

    永远记住:你必须从右到左阅读重定向链'from the end'( not 从左到右) .

  • 4

    我在重定向上找到了这篇精彩的帖子:All about redirections

    Redirect both standard output and standard error to a file

    $ command&>文件

    这个单行使用 &> 运算符将两个输出流(stdout和stderr)从命令重定向到文件 . 这是Bash快速将两个流重定向到同一目的地的快捷方式 .

    以下是Bash重定向两个流后文件描述符表的样子:

    如您所见,stdout和stderr现在都指向 file . 因此写入stdout和stderr的任何内容都会被写入 file .

    有两种方法可以将两个流重定向到同一目标 . 您可以一个接一个地重定向每个流:

    $ command> file 2>&1

    这是将两个流重定向到文件的更常见方法 . 第一个stdout被重定向到文件,然后stderr被复制到与stdout相同 . 所以两个流最终都指向 file .

    当Bash看到几个重定向时,它会从左到右处理它们 . 让我们完成这些步骤,看看会发生什么 . 在运行任何命令之前,Bash的文件描述符表如下所示:

    现在Bash处理第一个重定向>文件 . 我们之前已经看过这个,它使stdout指向文件:

    下一个Bash看到第二个重定向2>&1 . 我们之前没有见过这种重定向 . 这个复制文件描述符2是文件描述符1的副本,我们得到:

    两个流都已重定向到文件 .

    不过要小心!写作

    command> file 2>&1

    与写作不同:

    $ command 2>&1>文件

    重定向的顺序在Bash中很重要!此命令仅将标准输出重定向到文件 . stderr仍会打印到终端 . 要理解为什么会发生这种情况,让我们再次讨论这些步骤 . 所以在运行命令之前,文件描述符表如下所示:

    现在Bash处理从左到右的重定向 . 它首先看到2>&1所以它将stderr复制到stdout . 文件描述符表变为:

    现在Bash看到第二个重定向 >file ,它将stdout重定向到file:

    你看到这里发生了什么? Stdout现在指向文件,但是stderr仍然指向终端!写入stderr的所有内容仍会打印到屏幕上!所以要非常非常小心重定向的顺序!

    还要注意在Bash中写作

    $ command&>文件

    与以下内容完全相同:

    $ command>&file

  • 2

    0表示输入,1表示stdout,2表示stderr .

    One Tipsomecmd >1.txt 2>&1 是正确的,而 somecmd 2>&1 >1.txt 完全 wrong 没有效果!

  • 4

    如果您的系统上不存在 /foo/tmp 确实...

    $ ls -l /tmp /foo
    

    将打印 /tmp 的内容并打印 /foo 的错误消息

    $ ls -l /tmp /foo > /dev/null
    

    /tmp 的内容发送到 /dev/null 并打印 /foo 的错误消息

    $ ls -l /tmp /foo 1> /dev/null
    

    会做同样的事情(注意 1

    $ ls -l /tmp /foo 2> /dev/null
    

    将打印 /tmp 的内容并将错误消息发送到 /dev/null

    $ ls -l /tmp /foo 1> /dev/null 2> /dev/null
    

    将发送列表以及错误消息发送到 /dev/null

    $ ls -l /tmp /foo > /dev/null 2> &1
    

    是简写

  • 13

    从程序员的角度来看,它恰恰意味着:

    dup2(1, 2);
    

    man page .

    了解 2>&1 是一个副本也解释了为什么......

    command >file 2>&1
    

    ......和...不一样

    command 2>&1 >file
    

    第一个将两个流发送到 file ,而第二个将发送错误到 stdout ,普通输出发送到 file .

相关问题