繁体   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);
}

编译使用:

gcc -Wall text.c

然后在外壳中运行:

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

    结果:outfile的内容是:

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

    结果:

    这首先打印到终端: standard err, output.
    和outfile的内容是: standard output.

问题:

  • 我想问一下2 >& fd2 > file之间的区别。
    它们都等于函数dup()吗?

  • 另一个问题:为何超出文件内容:

      standard err, output. standard output. 

    我期望outfile的内容为:

      standard output. standard err, output 

实际上,在bash中, >&dup2非常相似。 也就是说,应用了文件描述符的文件描述符将与右边的描述符引用相同的文件。 所以:

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

它将stdout(1)重定向到文件outfile ,然后,dup2 stderr(2)引用与stdout(1)相同的文件。 也就是说,stdout和stderr都被重定向到该文件。

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

它将重定向stderr(2)引用与stdout(1)相同的文件,即控制台,然后,将重定向stdout(1)引用文件outfile 也就是说,stderr将输出到控制台,并将stdout输出到文件。

而这正是您所得到的。

范式混合


尽管有理由故意做所有这些事情,但是作为一种学习经验,在我可能称之为“域边界”的地方混合使用操作可能会造成混乱。

缓冲与非缓冲I / O

printf()被缓冲, write()是直接系统调用。 无论如何写操作都会立即发生,当输出是终端时,printf将(通常)逐行缓冲,而当输出是真实文件时,则逐块缓冲。 在文件输出的情况下(重定向),只有当您从main()返回或以其他方式调用exit(3)时,才会发生实际的printf输出,除非您打印了一堆东西。

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

比尔·乔伊(Bill Joy)在UCB编写的现在已经被遗忘的(但通常仍是默认安装的)csh,而一名研究生则拥有一些不错的功能,这些功能已导入到厨房水槽外壳中,或者与所有外壳功能一起想到。 是的,我在这里谈论bash。 因此,在csh中,重定向标准输出和标准错误的方法只是说cmd>&file ,这实际上比“官方” Bourne shell提供的工具包方法更加文明。 但是,伯恩(Bourne)语法在其他地方有其优点,无论如何,它仍然是占主导地位的范例。

但是,bash的“本机”重定向功能有些复杂,尽管其他功能似乎已经有了良好的开端,但我不会尝试在SO答案中对其进行总结。 无论如何,您在一个测试中使用了真正的bash重定向,而bash在另一个测试中也使用了传统的csh语法,并且该程序本身混合了范例。 从shell的角度来看,主要问题是重定向顺序在bash样式语法中非常重要,而csh样式语法仅指定最终结果。

2>&1部分使外壳程序执行以下操作:

dup2(1, 2);

这使fd 2成为fd 1的“副本”。

2> file被解释为

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

这将打开一个文件,并将filedescriptor放入插槽2。

这里有几个松散相关的问题。

样式注释:我建议使用2>&1不带空格。 我什至没有意识到间隔版本会起作用(我怀疑它在80年代中期没有在Bourne外壳中使用),而压缩版本是编写它的传统方法。

文件描述符I / O重定向符号在C shell及其衍生版本中并非全部可用; 它们可以在Bourne外壳及其衍生物(Korn外壳,POSIX外壳,Bash等)中使用。

shell必须要做的就是>file2>file2>&1之间的区别。 前两个安排将写到文件描述符的输出(第一种情况,即标准输出; 2情况下,即标准错误)输出到命名文件。 这意味着程序写入标准输出的所有内容都将保存到文件中。 第三个符号将2(标准错误)安排为与1(标准输出)相同的文件描述符; 写入标准错误的所有内容都将与标准输出一起放入同一文件。 它是使用dup2()轻松实现的。 但是,程序中的标准错误流将具有其自己的缓冲区,而程序中的标准输出流将具有其自己的缓冲区,因此,如果将输出转到文件,则输出的交织不会完全确定。

您以两种不同的方式运行命令,并且(毫不奇怪)获得了两种不同的结果。

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

    I / O重定向从左到右处理。 第一个将标准输出发送到outfile 第二发送标准误差同一个地方标准输出,所以它去outfile了。

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

    第一次重定向会将标准错误发送到要输出标准输出的位置,即当前的终端。 然后,第二次重定向将标准输出发送到文件(但是将标准错误发送到终端)。

该程序使用printf()函数和write()系统调用。 使用printf()函数时,它将缓冲其输出。 如果输出要发送到终端,则通常是“行缓冲”的,因此当将换行符添加到缓冲区时,将显示输出。 但是,当输出将要发送到文件时,它将被“完全缓冲”,并且只有在刷新或关闭文件流或填充缓冲区后,输出才会出现。 请注意, stderr尚未完全缓冲,因此写入其中的输出会立即显示。

如果在不进行任何I / O重定向的情况下运行程序,则会看到:

standard output. 
standard err, output

相比之下, write()系统调用立即将数据传输到输出文件描述符。 在该示例中,您写入标准错误,并且写入的内容将立即显示。 如果您使用了fprintf(stderr, ...)也会发生同样的情况。 但是,假设您修改了程序以写入STDOUT_FILENO; 然后,当输出到文件时,输出将按以下顺序显示:

standard err, output
standard output. 

因为在缓冲printf()同时write()是未缓冲的。

暂无
暂无

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

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