[英]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;
}
上面的代碼只是粗略估計整個事情是如何工作的,它不會檢查fread
、 fwrite
等的一些錯誤:你當然應該檢查最終程序中的錯誤。
也很容易看出如何擴展它以支持任意數量的 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
是描述符3
到6
的別名(因此寫入任何這些描述符的任何數據都將出現在stderr
中)或者您可以使用2<file_a 3<file_b 4<file_c
意味着您的程序將使用從file_a
重定向的文件描述符2
(stderr) 執行,並且文件描述符3
和4
已經從文件file_b
和file_c
打開。 可能應該設計一些符號(現在我並不容易想到,如何 devise 它)以允許在已啟動的不同進程之間進行管道(使用pipe(2)
系統調用)以執行某些任務,但您需要構建一個通用圖以實現通用性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.