尝试理解 bash 重定向语法及其输出

尝试理解 bash 重定向语法及其输出

我是 Linux 新手,正在尝试了解重定向的工作原理。

我一直在测试用于重定向到同一文件的各种语法stdoutstderr但这些语法并不都产生相同的结果。

例如,如果我尝试列出 2 个不存在的文件 (file1file2) 和 2 个存在的文件 (foofz):

语法 #1(没有重定向):

$ ls file1 foo fz file2

这是我在终端中得到的输出:

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo  fz

语法#2:

现在,通过重定向:

$ ls file1 foo fz file2 > redirect 2>&1

redirect文件包含与语法#1 相同的结果:

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz

因此,对于上述两种语法,shell 似乎stderr首先打印,然后stdout.

语法#3:

现在,如果我尝试使用以下语法之一:

$ ls file1 foo fz file2 > redirect 2> redirect

或者

$ ls file1 foo fz file2 2> redirect > redirect

然后该redirect文件将包含以下内容:

foo
fz
nnot access file1: No such file or directory
ls: cannot access file2: No such file or directory

在这里,它看起来像是stdout在 之前打印的stderr,但随后我们看到 的开头stderr被“裁剪”了与 相同数量的字符stdout

的长度stdout为 6 个字符(foo fz包括回车符),因此stderr( ls: ca) 的前 6 个字符已被 覆盖stdout。所以它实际上看起来像是stderr先打印出来的,然后stdout再打印出来stderr而不是附加到它上面。

stderr然而,如果是的话,对我来说会更有意义完全地删除并替换为stdout,而不是部分覆盖。

语法#4:

我发现纠正语法 #3 的唯一方法是将追加运算符添加到stdout

$ ls file1 foo fz file2 >> redirect 2> redirect

或者

$ ls file1 foo fz file2 2> redirect >> redirect

其结果与语法 #2 相同:

ls: cannot access file1: No such file or directory
ls: cannot access file2: No such file or directory
foo
fz

这篇文章在这里解释语法 #3 是错误的(大概语法 #4 也是错误的)。但出于争论的目的:为什么语法 #3 是错误的?它到底在说什么(或者不是告诉)shell 做什么而不是语法 #2?

stderr另外,输出总是显示在之前是否有原因stdout

谢谢你!

答案1

这就像运行两个进程同时写入同一个文件......这是个坏主意。您最终会得到两个不同的打开文件句柄,并且您的数据可能会出现乱码(如上面#3 中所示)。使用语法 #2 是正确的;它使文件句柄并将 stderr 和 stdout 指向同一位置。

至于 stderr 总是首先打印,对此没有任何规则。我怀疑ls这是因为ls需要检查目录中的每个条目,然后才能真正声明特定文件不存在。因此,它不是使 N 次遍历目录表,而是进行一次遍历,检查给定的所有命令行参数,报告错误,并打印找到的文件。其他命令可能会在 stdout 之后打印到 stderr,甚至在它们之间交替。

答案2

添加到通配符的答案中,stdout通常会被缓冲(存储在内存中以便稍后写出),而stderr从来不会(您希望显示错误消息,即使程序在写出任何内容之前崩溃)。所以stderr通常会更早出现。

答案3

不是这里的开发人员或内核专家。所以我无法评论任何代码,但在语法 #3 中,您使用两个不同的管道通过管道连接stdoutstderr同一个文件。因此,您将两个输出发送到的公共文件可能存在来自两个不同管道的资源争用问题。考虑到操作系统的非实时性质,两个管道可能同时将信息输入到同一个文件中。这可能可以解释缺失的字符。

在语法 #2 中,您将其重定向stderr到同一个管道,stdout此时,该文件有一个管道进入,并且 shell 根据竞争条件管理该管道。

这是我有根据的猜测,也只是猜测。没有什么可以证实这一点。

相关内容