繁体   English   中英

文件描述符可以重复多次吗?

[英]Can a file descriptor be duplicated multiple times?

我一直在寻找很长一段时间,找不到我的问题的答案。

我正在尝试通过完全重定向在 C 中重现 shell。 为了做到这一点,我想在执行命令之前打开文件。

例如,在ls > file1 > file2中,我使用dup2(file1_fd, 1)dup2(file2_fd, 1)然后执行ls来填充文件,但似乎标准的 output 只能打开一次,所以只有file2会被填充,因为它是最后一个被复制的。

有没有办法将标准 output 重定向到多个文件?

有什么我想念的吗? 谢谢!

有没有办法将标准 output 重定向到多个文件?

许多文件描述符不能成为一个文件描述符。 您需要分别写入每个文件描述符。 这就是tee实用程序为您所做的。

您所要求的是tee命令存在的确切原因(您可以在此处查看其源代码)。

您不能多次使用dup2()复制文件描述符。 正如您已经看到的,最后一个会覆盖任何先前的重复。 因此,您不能直接使用dup2()将程序的 output 重定向到多个文件。

为此,您确实需要多个描述符,因此您必须打开两个文件,使用popen()启动命令,然后从 pipe 读取并写入这两个文件。

这是一个非常简单的示例,说明如何做到这一点:

#include <stdio.h>
#include <stdlib.h>

#define N 4096

int main(int argc, const char *argv[]) {
    FILE *fp1, *fp2, *pipe;

    fp1 = fopen("out1.txt", "w");
    if (fp1 == NULL) {
        perror("fopen out1 failed");
        return 1;
    }

    fp2 = fopen("out2.txt", "w");
    if (fp2 == NULL) {
        perror("fopen out2 failed");
        return 1;
    }

    // Run `ls -l` just as an example.
    pipe = popen("ls -l", "r");

    if (pipe == NULL) {
        perror("popen failed");
        return 1;
    }

    size_t nread, nwrote;
    char buf[N];

    while ((nread = fread(buf, 1, N, pipe))) {
        nwrote = 0;
        while (nwrote < nread)
            nwrote += fwrite(buf + nwrote, 1, nread - nwrote, fp1);

        nwrote = 0;
        while (nwrote < nread)
            nwrote += fwrite(buf + nwrote, 1, nread - nwrote, fp2);
    }

    pclose(pipe);
    fclose(fp2);
    fclose(fp1);

    return 0;
}

上面的代码只是粗略估计整个事情是如何工作的,它不会检查freadfwrite等的一些错误:你当然应该检查最终程序中的错误。

也很容易看出如何扩展它以支持任意数量的 output 文件(仅使用FILE *数组)。

标准 output 与任何其他打开的文件没有什么不同,唯一的特殊特征是它是文件描述符1 (因此您的进程中只能有一个索引为 1 的文件描述符)您可以dup(2)文件描述符1来获取,假设文件描述符6 这是dup()的任务,只是为了获取另一个文件描述符(具有不同的编号)而不是您用作源的文件描述符,但对于相同的 source 重复的描述符允许您使用任何重复的描述符对 output 漠不关心,或者更改打开的标志,如关闭 exec标志或非块append标志(并非所有都是共享的,我不确定哪些可以更改而不影响其他人在重复)。 它们共享文件指针,因此您尝试对任何文件描述符的每个write()都将在其他文件描述符中更新。

但重定向的想法并非如此。 unix 中的一个约定说,每个程序都会收到三个已经从其父进程打开的描述符。 所以要使用分叉,首先你需要考虑如何编写符号来表示一个程序将接收(已经打开)多个加入流。 在这里,问题更加复杂,因为您需要表达如何将数据流合并为一个,这使得合并问题与问题相关。

File dup() ping 不是一种让文件描述符写入两个文件的方法……但反过来,它是一种让两个不同的文件描述符引用同一个文件的方法

做你想做的事情的唯一方法是在你要使用的每个文件描述符上重复write(2)调用。

正如一些答案所评论的那样, tee(1)命令允许您在 pipe 中分叉数据流,但不能使用文件描述符, tee(1)只是打开一个文件,然后write(2)将所有输入放在除了 write(2) 也将其写入标准输出。

shell 中没有规定分叉数据流,因为没有规定在输入时加入(并行)数据流。 我认为这是 Steve Bourne 在 shell 设计中的一些废弃想法,您可能会达到同样的观点。

顺便说一句,只需研究使用通用dup2()运算符的可能性,即 < n >& m >,但再次考虑,对于重定向程序, 2>&3 2>&4 2>&5 2>&6意味着你已预先打开 7 个文件描述符, 0 ... 6其中stderr是描述符36的别名(因此写入任何这些描述符的任何数据都将出现在stderr中)或者您可以使用2<file_a 3<file_b 4<file_c意味着您的程序将使用从file_a重定向的文件描述符2 (stderr) 执行,并且文件描述符34已经从文件file_bfile_c打开。 可能应该设计一些符号(现在我并不容易想到,如何 devise 它)以允许在已启动的不同进程之间进行管道(使用pipe(2)系统调用)以执行某些任务,但您需要构建一个通用图以实现通用性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM