协慌网

登录 贡献 社区

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

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

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

答案

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

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

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。

关于重定向的一些技巧

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

1 - 覆盖或追加?

符号>表示重定向

  • >意味着发送到整个已完成的文件 ,如果存在noclobber覆盖目标(请参阅#3之后的noclobber bash 功能)。
  • >>如果存在,则意味着发送除了将附加到目标。

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

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

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

好吧,有关重定向的一些小技巧, 在两个输出上执行不同的操作

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

附录:nota!使用新版本的>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

附录: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选项和>|一个词句法

这是关于覆盖

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 - 最后一招和更多......

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

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

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

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

man -Len -Pless\ +/^REDIRECTION bash

控制台;-)