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

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

 2>&1 

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

 g++ lots_of_errors 2>&1 | head 

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

我总是记不起这件事,而且我经常不得不去查看它,主要是因为我不完全理解这个特殊技巧的语法。 有人可以把这个分开来解释一个字符是什么“2>&1”的意思吗?

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

这里有一个方法来记住这个构造(尽pipe它不是完全准确的):首先, 2>1可能看起来像是将stderrredirect到stdout的一个好方法。 但是,它实际上会被解释为“将stderrredirect到名为1的文件”。 &表示接下来是文件描述符而不是文件名。 所以构造变成: 2>&1

 echo test > afile.txt 

redirect到afile.txt 。 这和做..一样

 echo test 1> afile.txt 

redirect标准错误,你做..

 echo test 2> afile.txt 

>&是将streamredirect到另一个文件描述符的语法 – 0是stdin。 1是stdout。 2是stderr。

您可以通过执行将stdoutredirect到stderr。

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

..或相反亦然:

 echo test 2>&1 

所以,总之.. 2>redirectstderr到一个(未指定的)文件,附加&1redirect标准输出到标准输出

关于redirect的一些技巧

对此的一些语法特殊性可能具有重要的行为。 有一些关于redirect, STDERRSTDOUT和参数sorting的小样本。

1 – 覆盖或附加?

符号>意味着redirect

  • >表示发送完整的文件 ,覆盖目标(如果存在的话)(见#3后面的noclobber bashfunction)。
  • >>意指如果存在则除了追加目标外。

任何情况下,文件将被创build,如果他们不存在。

2 – shell命令行依赖于顺序!

为了testing这个,我们需要一个简单的命令来发送两个输出

 $ 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 ---> 

请注意,本段中的最后一个命令行与之前的paraghaph中的命令行完全相同,在那里我写的似乎不是预期的行为 (所以这甚至可能是预期的行为)。

那么有一些关于redirect的技巧, 在两个输出上做不同的操作

 $ ( 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 

注意: &9描述符会自发发生,因为) 9>&2

附录:nota! 随着新版本的bash ( >4.0 ),有一个新的function和更性感的语法来做这种事情:

 $ 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 

附录: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通过一个特定的filter, STDERR到另一个,最后两个输出合并通过第三个命令filter。

3 – 一个关于noclobber选项和>| 句法

这是关于覆盖

set -o noclobber指示bash 覆盖任何现有文件时, >| 语法让你通过这个限制:

 $ 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 – 最后一招和更多…

为了redirect来自给定命令的输出,我们看到正确的语法可以是:

 $ 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 

4b-现在,我会让你想一想:

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

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

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

 man -Len -Pless\ +/^REDIRECTION bash 

在bash控制台;-)

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

  • 零是stdin
  • 一个是stdout
  • 两个是stderr

2>&1将fd 2redirect到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工具,使用非标准的文件描述符进行自定义日志logging,所以除非将其redirect到文件或其他东西,否则不会看到它。

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

您可以使用此方法将任何输出句柄redirect到另一个输出句柄,但最常用于将stdoutstderrstream引导到单个stream中进行处理。

一些例子是:

 # 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 – 它会将它redirect到参数遇到时的stdoutoutfile1 ), 然后stdoutredirect到outfile2

这允许一些相当复杂的欺骗。

我发现这个redirect的精彩文章: 所有关于redirect

将标准输出和标准错误redirect到一个文件

$命令&>文件

这一行代码使用&>操作符将两个输出stream(stdout和stderr)从命令redirect到文件。 这是bash快速将两个streamredirect到相同的目的地。

以下是在bashredirect两个stream后文件描述符表的外观: 在这里输入图像描述

正如你可以看到stdout和stderr现在指向文件。 所以写入stdout和stderr的任何东西都被写入文件。

有两种方法可以将两个streamredirect到同一个目的地。 您可以逐个redirect每个stream:

$ command> file 2>&1

这是将两个streamredirect到文件的更常见的方式。 第一个stdout被redirect到文件,然后stderr被复制为与stdout相同。 所以两个stream最终都指向文件。

当bash看到几个redirect时,它会从左向右处理它们。 我们来看看这些步骤是怎么发生的。 在运行任何命令之前,bash的文件描述符表如下所示:

在这里输入图像描述

现在bash处理第一个redirect>文件。 我们已经看到了这一点,它使stdout指向文件:

在这里输入图像描述

下一个bash会看到第二个redirect2>&1。 我们之前没有看到这个redirect。 这个复制文件描述符2是文件描述符1的副本,我们得到:

在这里输入图像描述

两个stream都被redirect到文件。

不过要小心! 写作:

命令>文件2>&1

写作不一样:

$命令2>&1>文件

redirect的顺序在bash中很重要! 该命令仅将标准输出redirect到文件。 stderr仍然会打印到terminal。 为了理解为什么会发生这种情况,我们再来一遍。 所以在运行命令之前,文件描述符表如下所示:

在这里输入图像描述

现在bash处理redirect从左到右。 它首先看到2>&1,所以它复制stderr到标准输出。 文件描述符表变成:

在这里输入图像描述

现在bash看到第二个redirect>文件,它将stdoutredirect到文件:

在这里输入图像描述

你看到这里发生了什么? Stdout现在指向文件,但stderr仍然指向terminal! 所有写到stderr的东西仍然会被打印到屏幕上! 所以要非常小心,redirect的顺序!

另外请注意,在bash中,写这个:

$命令&>文件

完全一样:

$命令>&文件

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

这对于所有输出需要分页时的“更多”有帮助。 有些程序将打印使用信息打印到stderr中。

帮助你记住

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

“2>&1”只是将发送到stderr的所有内容都指向标准输出。

我也build议阅读这篇文章的错误redirect在这个主题是全面详细介绍。

2是控制台标准错误。

1是控制台标准输出。

这是Unix的标准,Windows也遵循POSIX。 例如,当你跑步

 perl test.pl 2>&1 

标准错误被redirect到标准输出,所以你可以看到两个输出在一起。

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

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

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

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

我build议你试着去理解这些。

2>&1是一个POSIX shell结构。 这是一个细分,令牌令牌:


2 :“ 标准错误 ”输出文件描述符。

>&复制输出文件描述符运算符( 输出redirect运算符>一个变体)。 给定[x]>&[y] ,将由x表示的文件描述符设为输出文件描述符y的副本。

1标准输出 ”输出文件描述符。

expression式2>&1文件描述符2>&1复制到位置2 ,因此执行环境中写入2 (“标准错误”)的任何输出将转到原来由1 (“标准输出”)描述的相同文件。


进一步解释:

文件描述符 :“每进程唯一的非负整数,用于标识为文件访问而打开的文件”。

标准输出/错误 :请参阅shell文档redirect部分中的以下注释:

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

从程序员的angular度来看,这意味着:

 dup2(1, 2); 

看手册页 。

理解2>&1副本也解释了为什么…

 command >file 2>&1 

…不一样…

 command 2>&1 >file 

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

人们总是记得paxdiablo关于redirect目标的当前位置的暗示…这重要。

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

  • 想象&意思'and''add' (字符是一个悲剧 – 是不是?)
  • 因此,它变成: 'redirect2 (标准错误)到1 (标准输出)已经/当前所在的位置,并添加两个stream'

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

  • 想想&意义and或者add …(你有关于&符号的想法,是吗?)
  • 所以它变成: 'redirect1 (标准输出)到2 (stderr)已经/当前所在的位置,并添加两个stream'

永远记住:你必须从头到尾阅读redirect链,从右到左( 而不是从左到右)。

这就像把错误标记到标准输出或terminal。 即, cmd不是命令$ cmd 2> filename cat filename命令未find

发送到文件的错误就像发送到terminal的2>&1错误

redirectinput

input的redirect会导致文件描述符n中打开由单词扩展引起的名称的文件,或者读入文件描述符n的标准input(文件描述符0)(如果未指定n)。

redirectinput的一般格式是:

  [n]<word 

redirect输出

输出的redirect会导致文件描述符n中打开名称由扩展名引起的文件,如果未指定n,则输出标准输出(文件描述符1)。 如果该文件不存在,则创build它; 如果它确实存在,它将被截断为零大小。

redirect输出的一般格式是:

  [n]>word 

移动文件描述符

移动文件描述符redirect操作符

  [n]<&digit- 

将文件描述符数字移动到文件描述符n或标准input(文件描述符0),如果未指定n。 数字复制到n后closures。

同样,redirect操作符

  [n]>&digit- 

将文件描述符数字移动到文件描述符n或标准输出(文件描述符1)(如果未指定n)。

参考:

man bash
键入/^REDIRECT定位到redirection部分,了解更多..

在线版本在这里:
http://www.gnu.org/software/bash/manual/bashref.html#Redirections

PS:

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

假设你的系统中不存在/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 

是速记

0表示input,1表示标准输出,2表示标准错误。

一个提示somecmd >1.txt 2>&1是正确的,而somecmd 2>&1 >1.txt是完全错误的没有效果!