简体   繁体   English

在Unix / Linux shell编程中:>和>&之间的区别

[英]In the Unix/Linux shell programming:the difference between > and >&

int main(void)
{

  char buf[] = "standard err, output.\n";

  printf("standard output.\n");

  if (write(STDERR_FILENO,buf, 22) != 22)
      printf("write err!\n");

  exit(0);
}

Compile using: 编译使用:

gcc -Wall text.c

Then running in the shell: 然后在外壳中运行:

  1. ./a.out > outfile 2 >& 1

    Result:outfile´s content are: 结果:outfile的内容是:

     standard err, output. standard output. 
  2. ./a.out 2 >& 1 >outfile

    Result: 结果:

    This first prints to the terminal: standard err, output. 这首先打印到终端: standard err, output.
    and the content of outfile are: standard output. 和outfile的内容是: standard output.

Questions: 问题:

  • I want to ask the difference between 2 >& fd and 2 > file . 我想问一下2 >& fd2 > file之间的区别。
    Are they all equal to the function dup()? 它们都等于函数dup()吗?

  • Another question: why are the contents of outfile: 另一个问题:为何超出文件内容:

      standard err, output. standard output. 

    I expected the content of outfile to be: 我期望outfile的内容为:

      standard output. standard err, output 

Actually, in bash, >& is quite similar to dup2 . 实际上,在bash中, >&dup2非常相似。 That is, the file descriptor to which it is applied will refer to the same file as the descriptor to the right. 也就是说,应用了文件描述符的文件描述符将与右边的描述符引用相同的文件。 So: 所以:

$ ./a.out > outfile 2>& 1

It will redirect stdout(1) to the file outfile and, after that, will dup2 stderr(2) to refer to the same file as stdout(1). 它将stdout(1)重定向到文件outfile ,然后,dup2 stderr(2)引用与stdout(1)相同的文件。 That is, both stdout and stderr are being redirected to the file. 也就是说,stdout和stderr都被重定向到该文件。

$ ./a.out 2>& 1 >outfile

It will redirect stderr(2) to refer to the same file as stdout(1), that is, the console, and after that, will redirect stdout(1) to refer to the file outfile . 它将重定向stderr(2)引用与stdout(1)相同的文件,即控制台,然后,将重定向stdout(1)引用文件outfile That is, stderr will output to the console and stdout to the file. 也就是说,stderr将输出到控制台,并将stdout输出到文件。

And that's exactly what you are getting. 而这正是您所得到的。

Paradigm Mixing 范式混合


While there are reasons to do all of these things deliberately, as a learning experience it is probably going to be confusing to mix operations over what I might call "domain boundaries". 尽管有理由故意做所有这些事情,但是作为一种学习经验,在我可能称之为“域边界”的地方混合使用操作可能会造成混乱。

Buffered vs non-buffered I/O 缓冲与非缓冲I / O

The printf() is buffered, the write() is a direct system call. printf()被缓冲, write()是直接系统调用。 The write happens immediately no matter what, the printf will be (usually) buffered line-by-line when the output is a terminal and block-by-block when the output is a real file. 无论如何写操作都会立即发生,当输出是终端时,printf将(通常)逐行缓冲,而当输出是真实文件时,则逐块缓冲。 In the file-output case (redirection) your actual printf output will happen only when you return from main() or in some other fashion call exit(3), unless you printf a whole bunch of stuff. 在文件输出的情况下(重定向),只有当您从main()返回或以其他方式调用exit(3)时,才会发生实际的printf输出,除非您打印了一堆东西。

Historic csh redirection vs bash redirection 历史性的csh重定向vs bash重定向

The now-forgotten (but typically still in a default install) csh that Bill Joy wrote at UCB while a grad student had a few nice features that have been imported into kitchen-sink shells that OR-together every shell feature ever thought of. 比尔·乔伊(Bill Joy)在UCB编写的现在已经被遗忘的(但通常仍是默认安装的)csh,而一名研究生则拥有一些不错的功能,这些功能已导入到厨房水槽外壳中,或者与所有外壳功能一起想到。 Yes, I'm talking about bash here. 是的,我在这里谈论bash。 So, in csh, the way to redirect both standard output and standard error was simply to say cmd >& file which was really more civilized that the bag-of-tools approach that the "official" Bourne shell provided. 因此,在csh中,重定向标准输出和标准错误的方法只是说cmd>&file ,这实际上比“官方” Bourne shell提供的工具包方法更加文明。 But the Bourne syntax had its good points elsewhere and in any case survived as the dominant paradigm. 但是,伯恩(Bourne)语法在其他地方有其优点,无论如何,它仍然是占主导地位的范例。

But the bash "native" redirection features are somewhat complex and I wouldn't try to summarize them in a SO answer, although others seem to have made a good start. 但是,bash的“本机”重定向功能有些复杂,尽管其他功能似乎已经有了良好的开端,但我不会尝试在SO答案中对其进行总结。 In any case you are using real bash redirection in one test and the legacy-csh syntax that bash also supports in another, and with a program that itself mixes paradigms. 无论如何,您在一个测试中使用了真正的bash重定向,而bash在另一个测试中也使用了传统的csh语法,并且该程序本身混合了范例。 The main issue from the shell's point of view is that the order of redirection is quite important in the bash-style syntax while the csh-style syntax simply specifies the end result. 从shell的角度来看,主要问题是重定向顺序在bash样式语法中非常重要,而csh样式语法仅指定最终结果。

The 2>&1 part makes the shell do something like that: 2>&1部分使外壳程序执行以下操作:

dup2(1, 2);

This makes fd 2 a "copy" of fd 1. 这使fd 2成为fd 1的“副本”。

The 2> file is interpreted as 2> file被解释为

fd = open(file, ...);
dup2(fd, 2);

which opens a file and puts the filedescriptor into slot 2. 这将打开一个文件,并将filedescriptor放入插槽2。

There are several loosely related issues here. 这里有几个松散相关的问题。

Style comment: I recommend using 2>&1 without spaces. 样式注释:我建议使用2>&1不带空格。 I wasn't even aware that the spaced-out version works (I suspect it didn't in Bourne shell in the mid-80s) and the compressed version is the orthodox way of writing it. 我什至没有意识到间隔版本会起作用(我怀疑它在80年代中期没有在Bourne外壳中使用),而压缩版本是编写它的传统方法。

The file-descriptor I/O redirection notations are not all available in the C shell and derivatives; 文件描述符I / O重定向符号在C shell及其衍生版本中并非全部可用; they are avialable in Bourne shell and its derivatives (Korn shell, POSIX shell, Bash, ...). 它们可以在Bourne外壳及其衍生物(Korn外壳,POSIX外壳,Bash等)中使用。

The difference between >file or 2>file and 2>&1 is what the shell has to do. shell必须要做的就是>file2>file2>&1之间的区别。 The first two arrange for output written to a file descriptor (1 in the first case, aka standard output; 2 in the second case, aka standard error) to go to the named file. 前两个安排将写到文件描述符的输出(第一种情况,即标准输出; 2情况下,即标准错误)输出到命名文件。 This means that anything written by the program to standard output goes to file instead. 这意味着程序写入标准输出的所有内容都将保存到文件中。 The third notation arranges for 2 (standard error) to go to the same file descriptor as 1 (standard output); 第三个符号将2(标准错误)安排为与1(标准输出)相同的文件描述符; anything written to standard error goes to the same file as standard output. 写入标准错误的所有内容都将与标准输出一起放入同一文件。 It is trivially implemented using dup2() . 它是使用dup2()轻松实现的。 However, the standard error stream in the program will have its own buffer and the standard output stream in the program will have its own buffer, so the interleaving of the output is not completely determinate if the output goes to a file. 但是,程序中的标准错误流将具有其自己的缓冲区,而程序中的标准输出流将具有其自己的缓冲区,因此,如果将输出转到文件,则输出的交织不会完全确定。

You run the command two different ways, and (not surprisingly) get two different results. 您以两种不同的方式运行命令,并且(毫不奇怪)获得了两种不同的结果。

  1. ./a.out > outfile 2>&1

    I/O redirections are processed left to right. I / O重定向从左到右处理。 The first one sends standard output to outfile . 第一个将标准输出发送到outfile The second sends standard error to the same place as standard output, so it goes to outfile too. 第二发送标准误差同一个地方标准输出,所以它去outfile了。

  2. ./a.out 2>&1 >outfile

    The first redirection sends standard error to the place where standard output is going, which is currently the terminal. 第一次重定向会将标准错误发送到要输出标准输出的位置,即当前的终端。 The second redirection then sends standard output to the file (but leaves standard error going to the terminal). 然后,第二次重定向将标准输出发送到文件(但是将标准错误发送到终端)。

The program uses the printf() function and the write() system call. 该程序使用printf()函数和write()系统调用。 When the printf() function is used, it buffers its output. 使用printf()函数时,它将缓冲其输出。 If the output is going to a terminal, then it is normally 'line buffered', so output appears when a newline is added to the buffer. 如果输出要发送到终端,则通常是“行缓冲”的,因此当将换行符添加到缓冲区时,将显示输出。 However, when the output is going to a file, it is 'fully buffered' and output does not appear until the file stream is flushed or closed or the buffer fills. 但是,当输出将要发送到文件时,它将被“完全缓冲”,并且只有在刷新或关闭文件流或填充缓冲区后,输出才会出现。 Note that stderr is not fully buffered, so output written to it appears immediately. 请注意, stderr尚未完全缓冲,因此写入其中的输出会立即显示。

If you run your program without any I/O redirection, you will see: 如果在不进行任何I / O重定向的情况下运行程序,则会看到:

standard output. 
standard err, output

By contrast, the write() system call immediately transfers data to the output file descriptor. 相比之下, write()系统调用立即将数据传输到输出文件描述符。 In the example, you write to standard error, and what you write will appear immediately. 在该示例中,您写入标准错误,并且写入的内容将立即显示。 The same would have happened if you had used fprintf(stderr, ...) . 如果您使用了fprintf(stderr, ...)也会发生同样的情况。 However, suppose you modified the program to write to STDOUT_FILENO; 但是,假设您修改了程序以写入STDOUT_FILENO; then when the output is to a file, the output would appear in the order: 然后,当输出到文件时,输出将按以下顺序显示:

standard err, output
standard output. 

because the write() is unbuffered while the printf() is buffered. 因为在缓冲printf()同时write()是未缓冲的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM