在 Unix shell 中,如果我想将stderr
和stdout
组合到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。
关于此的一些语法特殊性可能具有重要的行为。有一些关于重定向, STDERR
, STDOUT
和参数排序的小样本。
符号>
表示重定向 。
>
意味着发送到整个已完成的文件 ,如果存在noclobber
覆盖目标(请参阅#3之后的noclobber
bash 功能)。 >>
如果存在,则意味着发送除了将附加到目标。 在任何情况下,如果文件不存在,将创建该文件。
为了测试它,我们需要一个简单的命令,它将在两个输出上发送一些东西 :
$ 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!使用新版本的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
附录: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
到另一个,最后两个输出合并通过第三个命令过滤器。
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
为了重定向给定命令的两个输出,我们看到正确的语法可能是:
$ 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
$ 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/
您可以通过点击阅读精细手册:
man -Len -Pless\ +/^REDIRECTION bash
在bash控制台;-)