jam*_*gni 58 shell file-descriptors
昨天我读了这个 SO 评论,它说在 shell 中(至少bash
)>&-
“与”具有相同的结果>/dev/null
。
该评论实际上将 ABS 指南称为其信息来源。但该消息来源说>&-
语法“关闭文件描述符”。
我不清楚关闭文件描述符和将其重定向到空设备这两个操作是否完全等效。所以我的问题是:是吗?
从表面上看,关闭描述符就像关闭一扇门,但将其重定向到空设备似乎打开了一扇通往地狱的大门!两者对我来说似乎并不完全相同,因为如果我看到一扇关着的门,我不会尝试从里面扔出任何东西,但是如果我看到一扇敞开的门,我会认为我可以。
换句话说,我一直想知道是否>/dev/null
意味着cat mybigfile >/dev/null
实际上会处理文件的每个字节并将其写入/dev/null
忘记它。另一方面,如果 shell 遇到一个关闭的文件描述符,我倾向于认为(但我不确定)它不会写任何东西,尽管问题仍然是是否cat
仍会读取每个字节。
这个评论说>&-
和>/dev/null
“应该”是一样的,但对我来说并不是那么响亮的答案。我想有一个更权威的答案,参考标准或源核心与否......
Sté*_*las 71
不,你当然不希望关闭文件描述符0,1和2。
如果这样做,应用程序第一次打开文件时,它会变成 stdin/stdout/stderr...
例如,如果你这样做:
echo text | tee file >&-
Run Code Online (Sandbox Code Playgroud)
当tee
(至少一些实现,比如busybox')打开文件进行写入时,它将在文件描述符1(stdout)上打开。所以tee
将写入text
两次file
:
$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193) = 5
write(1, "text\n", 5) = 5
write(1, "text\n", 5) = 5
read(0, "", 8193) = 0
exit_group(0) = ?
Run Code Online (Sandbox Code Playgroud)
众所周知,这会导致安全漏洞。例如:
chsh 2>&-
Run Code Online (Sandbox Code Playgroud)
并且chsh
(setuid 应用程序)最终可能会在/etc/passwd
.
一些工具甚至一些库试图防止这种情况发生。例如,如果 GNUtee
为写入而打开的文件被分配为 0、1、2,而 busyboxtee
不会,则GNU会将文件描述符移动到 2 以上的 1 。
大多数工具,如果它们无法写入 stdout(例如因为它未打开),则会在 stderr 上报告错误消息(使用用户的语言,这意味着打开和解析本地化文件需要额外的处理......),所以这将显着降低效率,并可能导致程序失败。
无论如何,它不会更有效率。该程序仍将执行write()
系统调用。如果程序在第一次失败的write()
系统调用后放弃写入 stdout/stderr,它只会更有效率,但程序通常不会这样做。他们通常要么出错退出,要么继续尝试。
use*_*ser 14
IOW 我一直想知道是否
>/dev/null
意味着cat mybigfile >/dev/null
实际上会处理文件的每个字节并将其写入/dev/null
忘记它。
这不是您问题的完整答案,但是是的,上面是它的工作原理。
cat
读取命名文件,如果没有命名文件,则读取标准输入,并将这些文件的内容输出到其标准输出,直到遇到最后一个命名文件(包括标准输入)的 EOF。这就是它的工作。
通过添加,>/dev/null
您将标准输出重定向到 /dev/null。这是一个特殊的文件(一个设备节点),它会丢弃写入其中的任何内容(并在读取时立即返回 EOF)。请注意,I/O 重定向是由 shell 提供的功能,而不是由每个单独的应用程序提供,并且名称/dev/null并没有什么神奇之处,只是在大多数类 Unix 系统上恰好存在。
同样重要的是要注意,设备节点的具体机制因操作系统而异,但 cat(在 GNU 系统中,表示 coreutils)是跨平台的(相同的源代码至少需要在 Linux 和Hurd),因此不能依赖于特定的操作系统内核。此外,如果您使用另一个名称创建 /dev/null 别名(在 Linux 上,这意味着具有相同主要/次要设备编号的设备节点),它仍然有效。并且总是有写其他地方的情况,它的行为实际上是相同的(比如,/dev/zero)。
因此,cat
它不知道 /dev/null 的特殊属性,并且确实很可能一开始也不知道重定向,但它仍然需要执行完全相同的工作:它读取命名文件,并输出/那些文件到其标准输出。的标准输出cat
碰巧进入一个空白并不是它cat
本身所关心的。
归档时间: |
|
查看次数: |
4712 次 |
最近记录: |