linux下的stdin,stdout和stderr
參考自
在linux中經常會看到stdin,stdout和stderr,這3個可以稱為終端(Terminal)的標準輸入(standard input),標準輸出(standard out)和標準錯誤輸出(standard error)。
通過man stdin檢視手冊,可以看到它們都是在stdio.h中定義的。當linux開始執行程式的時候,程式預設會開啟這3個檔案流,這樣就可以對終端進行輸入輸出操作。
下面用c語言模擬下這3個檔案流。
標準輸入(standard input)
在c語言中表現為呼叫scanf函式接受使用者輸入內容,即從終端裝置輸入內容。也可以用fscanf指明stdin接收內容。 標準輸入的檔案識別符號為0
#include <stdio.h>
intmain(void)
{
charstr[10];
scanf("%s", str);
fscanf(stdin, "%s", str);
return0;
}
標準輸出(standard out)
在c語言中表現為呼叫printf函式將內容輸出到終端上。使用fprintf也可以把內容輸出到終端上。標準輸出的檔案識別符號為1。
#include <stdio.h>
intmain(void)
{
printf("%s\n", "hello");
fprintf (stdout, "%s\n", "hello");
return0;
}
標準錯誤輸出(standard error)
標準錯誤和標準輸出一樣都是輸出到終端上, 標準錯誤輸出的檔案識別符號為2。
在程式處理的時候,正常的資訊輸出作為標準輸出,產生錯誤的輸出作為標準錯誤輸出。這樣在重定向的時候,就可以將正常的資訊和錯誤的資訊重定向到不同的檔案。
#include <stdio.h>
intmain(void)
{
printf("%s\n", "hello");
fprintf(stderr, "%s\n", "error");
return0;
}
上面這個程式分別往終端和stderr輸出了資訊,編譯這個程式生成二進位制檔案a.out,使用下列命令執行,重定向輸出。
# 1是stdout的檔案識別符號,而2是stderr的檔案識別符號
# "hello\n"重定向(輸出)至log.txt,而"error\n"重定向至error.txt
./a.out 1>log.txt 2>error.txt
這樣就把輸出的內容hello儲存到了log.txt檔案,錯誤的資訊error儲存到了error.txt檔案。(也就是通過管道重定位)
在c語言裡,也可以使用freopen函式重定向輸出流
#include <stdio.h>
intmain(void)
{
FILE*out = freopen("out.txt", "w", stdout);
printf("%s\n", "hello");
return0;
}
上例程式碼編譯執行後,終端上並沒輸出內容,而是儲存到了out.txt這個檔案了。
stdout與stderr的區別
1. 在linux中,標準輸出和標準錯誤預設都是將資訊輸出到終端上,那麼他們有什麼區別呢?
讓我們來看個題目:
問題:下面程式的輸出是什麼?
#include <stdio.h>
int main()
{
fprintf(stdout,"Hello ");
fprintf(stderr,"World!");
return 0;
}
答案是:World!Hello
這是為什麼呢?**在預設情況下,stdout是行緩衝的,它的輸出會先放在一個buffer裡面,只有到換行的時候,才會輸出到螢幕;而stderr是無緩衝的,會直接輸出。**舉例來說就是fprintf(stdout, “xxxx”) 和 fprintf(stdout, “xxxx\n”),前者在返回時並不重新整理buffer,直到遇到新行或函式返回時才會重新整理緩衝區並輸出;而fprintf(stderr, “xxxxx”),不管有沒有’\n’,都直接輸出。
首先,程式執行第一條列印語句時,由於stdout是行緩衝,而這裡沒有換行符,所以函式返回,要列印的內容還留在緩衝區裡; 然後,執行第二條列印語句,由於stderr是無緩衝,World!直接列印在終端上; 最後,函式執行返回語句return,緩衝區中的Hello 此時被沖洗,在終端打印出來。
所以,整個程式的執行結果就是:World!Hello
2. 當stdout、stderr遇到重定向,會發生什麼?
問題:下面的程式gcc編譯之後分別執行下面兩個命令,結果分別是什麼?
./a.out 1>stdout.file
./a.out 2>stderr.file
#include <stdio.h>
int main()
{
printf("a\n");
fprintf(stdout,"b\n");
fprintf(stderr, "c\n");
return 0;
}
結果:
# a, b輸出至stdout.file,而螢幕顯示c
./a.out 1>stdout.file
# c輸出至stderr.file,而螢幕顯示a, b
./a.out 2>stderr.file
總結
總的來說,stdin,stdout和stderr還是和終端有密切關係,通常在生產環境時,會將這3個流重定向到其它檔案。