bash - shell重定向追加 - 文件重定向




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

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

2>&1

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

g++ lots_of_errors 2>&1 | head

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

我总是无法记住这一点,而且我经常不得不去查看它,主要是因为我没有完全理解这个特殊技巧的语法。 有人可以分解这个并且逐字解释什么是“2>&1”吗?


重定向输入

输入的重定向会导致文件描述符n的文本描述符n将被打开以读取字的扩展名,如果未指定n,则输入标准输入(文件描述符0)。

重定向输入的一般格式是:

      [n]<word

重定向输出

输出的重定向会导致文件的名称由单词的扩展名开始写入文件描述符n,如果未指定n,则标准输出(文件描述符1)。 如果文件不存在,则创建该文件; 如果它确实存在,则它被截断为零大小。

重定向输出的一般格式是:

      [n]>word

移动文件描述符

移动文件描述符重定向操作符

      [n]<&digit-

如果未指定n,则将文件描述符数字移至文件描述符n或标准输入(文件描述符0)。 数字复制到n后关闭。

同样,重定向操作符

      [n]>&digit-

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

参考:

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

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

PS:

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


关于重定向的一些技巧

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

1 - 覆盖或追加?

符号>意味着重定向

  • >表示将整个完整文件发送 ,覆盖目标(如果存在)(请参阅#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 --->

请注意,本段中的最后一条命令行与之前的paraghaph完全相同,我写的看起来并不是预期的行为 (因此,这甚至可能是预期的行为)。

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

$ ( 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 ),有一个新功能和更具性感的语法来完成这种事情:

$ 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

在bash控制台中;-)


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。

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


2>&1是一个POSIX shell构造。 这里是一个细分,按令牌标记:

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

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

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

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

进一步解释:

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

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

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


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

dup2(1, 2);

查看手册页

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

command >file 2>&1

...不一样...

command 2>&1 >file

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


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

是速记


数字指的是文件描述符(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工具,它们使用非标准文件描述符进行自定义日志记录,所以除非将其重定向到文件或其他东西,否则不会看到它。


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

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


该构造将标准错误流( 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

这允许一些非常复杂的欺骗。


这就像将错误压缩到标准输出或终端一样。 即。 cmd不是命令$ cmd 2> filename cat filename命令未找到

发送到文件的错误就像发送到终端的2>&1错误那样





redirect