是否可以得出 4 种类型的结论?流输出如果我们不希望它们在执行命令后出现在 CLI 中,我们可以引用 Linux 中的文件吗?
对文件的可能引用:
- 所有流输出
- 仅标准错误
- 仅标准输出(包括标准输出的最终结果)。
- stdout 和 stderr(不包括 stdout 的最终结果)。
笔记:
数字 4 的一个例子可能是find / -type f -name php.ini 2>/dev/null
。据我了解,使用这个命令我们没有得到标准错误,也没有标准输出(除了标准输出的最终结果在本例中,这是我们搜索的文件(如果找到)。
答案1
有两个输出流连接到 Unix 系统上的每个进程:标准输出(标准输出,文件描述符 1)和标准误(stderr,文件描述符 2)。这些可以彼此独立地重定向。标准输入使用文件描述符 0。
- 要将标准输出重定向到文件
file
,请使用>file
或更明确的1>file
。替换file
为/dev/null
丢弃数据。 - 要将标准错误重定向到文件
file
,请使用2>file
. - 要将标准错误重定向到标准输出所在的位置,请使用
2>&1
. - 要将标准输出重定向到标准错误所在的位置,请使用
1>&2
.
不存在流或过程的“最终结果”概念。我想发送到标准输出的任何内容都可以被视为进程的“结果”,除非它也将数据输出到它自己打开的某个文件或具有其他副作用(例如从目录中取消文件链接,在这种情况下)的rm
,或在 ) 的情况下处理多个网络连接sshd
。进程还返回退出状态(零表示“成功”,非零表示“失败”),可以将其视为该进程的“结果”,但这不一定与进程的输出流相关。
流也可以重定向到附加模式,这意味着如果重定向到文件,则该文件最初不会被截断,并且流上的任何数据都将附加到文件末尾。通过使用>>file
而不是来做到这一点>file
。
在问题的注释中,命令
find / -type f -name php.ini 2>/dev/null
给出。这会重定向(丢弃)仅有的标准误差。标准输出流根本不重定向,因此在控制台或终端中完整可见。如果它是管道的中间部分,则标准输出流将被输入到管道中下一个命令的标准输入中。
总而言之,我想说有二(不是四个)输出流。这些可以以各种方式独立地重定向,其中包括丢弃它们的内容。
答案2
每一个过程按照惯例,可以使用三个标准文件描述符。这些文件描述符可作为流使用:stdin
、stdout
和stderr
。
默认情况下,当您从 shell (CLI) 启动进程时,第一个进程连接到终端(或终端仿真器,如 xterm)的输入,另外两个连接到终端的输出。
您可以指示 shell 将它们重定向到其他地方,例如/dev/null
(它们被吞噬的地方)。您可以独立为stdout
和执行此操作stderr
。那么对于这种情况,确实有四种可能:
command
command > /dev/null
command 2> /dev/null
command > /dev/null 2> /dev/null
但没有什么可以阻止您将其中一个或两个重定向到其他地方:
command > /tmp/myout 2> /tmp/myerr
在这种情况下,您的终端也不会得到任何输出,但您可以稍后在文件/tmp/myout
和中读取它/tmp/myerr
。
答案3
情况比你的问题所暗示的更简单,也更复杂。来解释一下什么善行难陀说在他的回答,有两个按惯例配置并用于输出的标准(常规)I/O 流(文件描述符):stdout(文件描述符 1)和 stderr(文件描述符 2)。我们的规范问题, shell 的控制和重定向运算符是什么?,讨论如何重定向它们。天真地,我们可以列举五种不同的组合:
╔══════════════════════════════╦═════════════════════════════════════════════╗
║ ║ stderr ║
║ ╟─────────────────────┬───────────────────────╢
║ ║ default │ ║
║ ║ (same as the shell) │ redirected ║
╠════════╤═════════════════════╬═════════════════════╦═══════════════════════╣
║ │ default ║ ║ ║
║ │ (same as the shell) ║ 1 ║ 2 ║
║ ├─────────────────────╠═════════════════════╬═══════════════════════╣
║ stdout │ ║ ║ 4. redirected ║
║ │ ║ ║ to the same file ║
║ │ redirected ║ 3 ╟───────────────────────╢
║ │ ║ ║ 5. redirected ║
║ │ ║ ║ to different files ║
╚════════╧═════════════════════╩═════════════════════╩═══════════════════════╝
但如果你算作/dev/null
与文件不同,追加模式作为一种特殊情况,读写模式与只写模式不同,管道与文件不同,那么组合的数量就会呈指数级增长。然而,正如反复指出的,“stdout 的最终结果”不是标准的 Unix/Linux/bash 短语。
只有两个?
其他答案(也许是明智的)将自己限制为 stdout 和 stderr (文件描述符 1 和 2)。我(鲁莽地?)相信这个问题的完整答案应该解决其他文件描述符可用的事实 - 最多数百,数千,甚至超过一百万。例如,如果运行类似 的命令diff file1 file2
,diff
程序将打开file1
和file2
,内核可能会分配文件描述符 3 和 4。不同之处在于,只有文件描述符 0、1 和 2 是预先定义的。以下位置讨论了重定向大于 2 的文件描述符:
- Bash 参考手册:第 3.6 节重定向
- 高级 Bash 脚本指南:第 20 章 I/O 重定向
- 2>&-、2>/dev/null、|&、&>/dev/null 和 >/dev/null 2>&1 之间的区别(U&L问题)
- 除了通常的 stdin/stdout/stderr (0, 1, 2) 之外,我们还能有更多的文件描述符吗?(堆栈溢出问题)
例如,请参阅以下高文件描述符示例:
$ 猫犬.c #include <stdio.h> #include <字符串.h> 主要的() { int i,len; char msg[] = "你好,狗。\n"; len = strlen(msg); 我=写(17,味精,长度); 如果 (i == len) printf("成功!i = %d = len\n", i); 否则如果 (i == -1) { printf("错误!i = %d (len = %d)\n", i, len); 错误(“”); } 别的 printf("意外结果:i = %d, len = %d\n", i, len); } $ 制作犬类 cc 犬.c -o 犬 $ ./犬类 错误!我 = -1 (len = 12) 错误的文件描述符 $ ./canine 17> 动物 成功!我 = 12 = 长度 $ ls -l 总计 70 -rw-r--r-- 1我的用户名 我的组名 2012年4月12日 13:36 动物 -rwxr-xr-x 1我的用户名 我的组名67067 4 月 12 日 13:36 犬 -rw-r--r-- 1我的用户名 我的组名 358 四月 12 13:36 犬.c $ 猫 动物 你好,狗。
警告:我不确定上述内容是否适用于所有 shell 的所有版本。
标准程序不会写入高于 2 的文件描述符(除非它们通过打开文件、建立网络连接或类似操作从内核获取该文件描述符)。但是,如果您有一个执行此操作的(非标准)程序,则可以重定向这些文件描述符。
而且,如果您只有 100 个文件描述符,并且仅考虑每个文件描述符是否被重定向,那么您就有超过十亿 (1,000,000,000,000,000,000,000,000,000,000) 种可能的组合。