2014-10-02 25 views
3

的UNIX手冊頁unistd.h狀態:我可以創建與stdout和stderr不同的自己的輸出流嗎?

The following symbolic constants are defined for file streams: 
STDIN_FILENO File number of stdin. It is 0. 
STDOUT_FILENO File number of stdout. It is 1. 
STDERR_FILENO File number of stderr. It is 2. 

grepping我所有的頭文件,我覺得這是真的。

[/usr]grep -r "STDIN_FILENO" include 
include/unistd.h:#define STDIN_FILENO 0 /* Standard input. */ 

[/usr] grep -r "STDOUT_FILENO" include 
include/unistd.h:#define STDOUT_FILENO 1 /* Standard output. */ 

[/usr]grep -r "STDERR_FILENO" include 
include/boost/asio/detail/impl/handler_tracking.ipp: ::write(STDERR_FILENO, line, length); 
include/unistd.h:#define STDERR_FILENO 2 /* Standard error output. */ 

即使它們被定義,它們似乎永遠不會被我的機器上的任何其他std頭文件使用。我覺得很奇怪。或許0,1和2用於別處而不是定義的宏。這些宏只是作爲流如何配置的指示而被引用。

無論如何,我們可以通過這樣捕捉到外殼特定輸出流:

./program 1> stdout.txt 
./program 2> stderr.txt 
./program > both.txt 2>&1 

我要創造我自己的輸出流,並通過這樣捕獲它:

./program 3> mine.txt 

我嘗試搜索unistd.h<iostream>包含的其他文件,以瞭解std::coutstd::cerr如何工作,但正如您可能想象的那樣,我迷失了方向並感到困惑。

我更關心你是否可以做到這一點,而不是它是否是一個好主意。

+1

看一看Bash文檔。文件描述符通過bash從登錄或終端程序繼承,然後由程序繼承。 – 2014-10-02 01:49:17

+0

如果你使用的是GCC,你可能會發現它的非標準庫有用:''它允許你創建一個'std :: filebuf'(以及一個'std :: fstream')一個POSIX文件描述符。 – Galik 2014-10-02 02:38:31

回答

3

打開的文件描述符由子進程繼承。操作系統負責連接一個進程與三個標準流,但您可以自由地執行任何數量的open() s,然後是exec()(最好在之前的fork()之後)。然後,孩子可以掃描打開的文件描述符列表(在/proc/self/fd/中)或以某種方式「知道」要使用哪一個。

下面是用C寫的

#include <errno.h> /* errno      */ 
#include <stdio.h> /* atoi, fprintf    */ 
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */ 
#include <string.h> /* strerror, strlen    */ 
#include <unistd.h> /* write      */ 

static const char *const message = "hello, world\n"; 

int main(int argc, char * * argv) 
{ 
    int fd; 
    int i; 
    for (i = 1; i < argc; ++i) 
    { 
     fd = atoi(argv[i]); 
     if (write(fd, message, strlen(message)) < 0) 
     { 
      fprintf(stderr, "error: cannot write to fd %d: %s\n", 
        fd, strerror(errno)); 
      return EXIT_FAILURE; 
     } 
    } 
    return EXIT_SUCCESS; 
} 

程序的調用者負責打開任何文件描述符的程序應寫入,因此通過它的命令行參數告訴它的一個小例子。

要傳遞連接到文件redir的打開文件描述符3,我們可以使用shell的exec實用程序打開文件描述符並執行該子文件。

$ exec 3>redir ./a.out 3 

這將孩子退出後,關閉當前的外殼,所以你可能想嘗試一下在一個子shell:

$ sh -c 'exec 3>redir ./a.out 3' 

,或者,不使用exec但重定向語法@提到bmargulies。在這裏,我們寫入標準錯誤輸出(2),以及寫入文件描述符3和4,我們將3重定向到標準輸出(1),將4重定向到文件redir

$ ./a.out 2 3 4 3>&1 4>redir 
hello, world 
hello, world 
$ cat redir 
hello, world 

文件描述符的這種繼承被大量使用在讓他們的(授權)兒童有文件描述符到日誌文件服務器進程,他們chroot()監獄,TCP連接之外的文件並沒有什麼別的。

不幸的是,忘記在exec()之前關閉文件描述符是一個常見的錯誤,可能與安全性有關。有一個Valgrind模塊來檢查這一點。

4

當您撥打open時,它會返回一個數字。您將該號碼傳遞給readwrite。你可以,但是,運行像這樣的命令:

mycommand 3 3>bloop.txt 

而且裏面mycommand的,轉換的argv [1]爲數字,並通過它來寫。

+0

啊,這個函數的第一個參數。文件描述符(fd) http://man7.org/linux/man-pages/man2/write.2.html – 2014-10-02 01:49:23

相關問題