将标准错误重定向到c中的文件
Posted
技术标签:
【中文标题】将标准错误重定向到c中的文件【英文标题】:Redirecting standard error to a file in c 【发布时间】:2022-01-05 06:32:27 【问题描述】:我正在用 c 语言制作自己的 shell,现在我正在尝试创建一个函数,将 shell 的标准错误重定向到特定文件,该选项可以显示标准错误当前的去向以及另一个能够将 stderr 重置为原来的样子。
我已经实现了这段代码来重定向标准错误:
int fd, new_fd;
if((fd = open(tokens[1], O_RDWR)) == -1)
perror("Error opening: ");
return 0;
if(dup2(fd, STDERR_FILENO) == -1)
perror("Error: ");
if(close(fd) == -1)
perror("Error closing: ");
现在,我找不到任何可以恢复或显示标准错误的选项的东西,如果有人可以帮助我实现这一点,那就太棒了!
if(tokens[1] == NULL)
//Shows where the standard error is currently going to
return 0;
if(strcmp(tokens[1], "-reset") == 0)
//Restores the standard error to what it was originally
return 0;
【问题讨论】:
tokens[1] 在第一个代码中是文件名! 如果你将stderr
重定向到一个文件(如第一个sn-p所示),那么你知道文件名 - 将它保存到一个局部变量/文件中以便持久化,并显示它根据要求发给用户。如果我误解了您 - 请添加一些有关每个 sn-p 代码运行的上下文的信息。
我明白你所说的,并会这样做来显示它,但在默认情况下,我应该显示什么文件,默认情况下 stderr 所在的文件是什么?
通常一个shell重定向一个子进程的输出,而不是它自己的输出。
您是否使用标准 shell(如 bash)来运行您的 shell?在这种情况下,我相信stderr
会像往常一样打印到屏幕上。正如上面的评论所说 - 你应该将你的 shell 的 stderr
和你的 shell 的子进程的 stderr
分开。
【参考方案1】:
要恢复stderr
,请在替换之前使用dup
将原始文件描述符保存到新的文件描述符中。如果您愿意,您可以稍后从该备份中恢复它。如果你不这样做,只是用你打开的文件替换它,它将丢失,因为dup2
关闭它替换的描述符,这样旧的stderr
的唯一描述符就丢失了。
int backup = dup(STDERR_FILENO);
// ... later
dup2(backup, STDERR_FILENO);
更新
获取文件描述符的名称通常是不可能的,唯一的原因是这不是一对一的映射。如果一个文件描述符引用了一个不能保证以开头的文件(它可能是一个套接字、管道、共享内存对象等),那么这个文件可能在一个甚至多个中以不同的名称多次存在不同的目录;只需使用ln
而不使用-s
硬链接文件,您就有两个文件名都指向同一个文件。
也许下面的心理图像更清楚:想象一个文件是一个由数字引用的磁盘存储。目录条目只是将名称映射到文件编号的查找表,当然,多个名称可能映射到同一个文件编号。如果您使用名称打开文件,则该名称仅用于查找其编号一次,实际访问使用该编号进行。打开文件后,您获得的文件描述符仅链接到文件本身,因此它只需要文件号。即使您正在写入文件,文件名甚至可能会更改,因为此处更改的只是映射引用。
您可以在文件描述符上使用fstat
来获取它引用的文件的struct stat
描述,也就是说,如果它确实引用了一个文件,但是您可能会注意到,这个结构不包含名称。它只包含文件号(st_ino
)。
在包括 macOS 在内的 BSD 系统上,您可以使用命令 F_GETPATH
调用 fcntl
并获得用于打开的路径;系统会在某处记住该路径。
在 Linux 上,此选项不存在。您唯一的选择是在/proc/self/fd/X
上调用readlink
,其中X
是文件描述符编号。这还将为您提供用于打开的文件的路径。
请记住,这不能保证是该文件的唯一名称,并且在您进行该调用的那一刻,文件名可能已经更改,或者该文件甚至可能不再存在,就像删除了打开的文件一样,一次只删除目录条目,但只要仍有至少一个活动文件描述符引用它,文件本身就会保持存在;一旦最后一个描述符关闭,文件本身就会被删除(这意味着它消耗的空间被添加回磁盘的空闲池,并且可能被其他文件重用)。
【讨论】:
谢谢,会落实的!你知道我怎么能打印出 stderr 目前所在的文件名吗? @rascadux 我更新了关于如何获取文件路径的答案以及解释为什么这通常是不可能的,即使你解决它,你可能并不总是得到预期的结果跨度>以上是关于将标准错误重定向到c中的文件的主要内容,如果未能解决你的问题,请参考以下文章