簡體   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