将标准错误重定向到c中的文件

Redirecting standard error to a file in c

我正在用 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: ");
}

现在,我找不到任何选项来恢复或显示 stderr 现在的去向,如果有人可以帮助我实现这一点,那就太棒了!

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;
}

要恢复 stderr,请在替换前使用 dup 将原始文件保存到新的文件描述符。如果您愿意,您可以稍后从该备份中恢复它。如果你不这样做,只是用你打开的文件替换它,它将丢失,因为 dup2 关闭它替换的描述符,这样旧的 stderr 唯一的描述符是迷路了。

int backup = dup(STDERR_FILENO);
// ... later
dup2(backup, STDERR_FILENO);

更新

获取文件描述符的名称通常是不可能的,唯一的原因是这不是一对一的映射。如果一个文件描述符引用一个文件,它不能保证以开头(它可能是一个套接字,一个管道,一个共享内存对象等),这个文件可能在一个甚至多个中以不同的名称存在多次不同的目录;只是硬 link 文件使用 ln 而没有 -s 并且你有两个文件名都指向同一个文件。

也许下面的心理形象更清楚:想象一个文件是由一个数字引用的一块磁盘存储。目录条目只是将名称映射到文件编号的查找表,当然,多个名称可以映射到相同的文件编号。如果您使用名称打开文件,则该名称仅用于查找其编号一次,实际访问是使用该编号进行的。文件打开后,您获得的文件描述符仅 linked 到文件本身,因此它只需要文件编号。即使您正在写入文件,文件名甚至可能会更改,因为此处更改的只是映射引用。

您可以在文件描述符上使用 fstat 以获得它引用的文件的 struct stat 描述,也就是说,如果它确实引用了一个文件,但您可能会注意到,这结构不包含名称。它只包含文件编号(st_ino)。

BSD系统,包括macOS,可以调用fcntl命令F_GETPATH,得到打开的路径;系统简单地记住了某处的路径。

在 Linux 此选项不存在。您唯一的选择是在 /proc/self/fd/X 上调用 readlink,其中 X 是文件描述符编号。这还将为您提供用于打开的文件的路径。

请记住,这不能保证是该文件的唯一名称,并且在您调用该文件的那一刻,文件名可能已经更改或者该文件可能不再存在,就像打开的文件一样被删除,只有目录条目被立即删除,但文件本身保持存在,只要仍然有至少一个活动文件描述符引用它;一旦最后一个描述符关闭,文件本身就会被删除(这意味着它消耗的 space 添加回磁盘的空闲池并可以被其他文件重用)。