HTTP 狀態消息
810
2022-05-28
在命令行運行程序時,可以用“>"運算符把標準輸出重定向到文件:
~/Desktop/Mc$ echo "hello world" > log.txt ~/Desktop/Mc$ tail -f log.txt hello world
1
2
3
標準輸入、標準輸出、標準錯誤是三大默認數據流,除此之外還有其他形式的數據流,如文件連接和網絡連接也屬于數據流。數據流就是流動的數據,數據從一個進程流出,然后流入另一個進程。
重定向進程的輸出,相當于改變進程發送數據的方向。如上面的例子,原本標準輸出會把數據發送到屏幕,現在讓它把數據發送到文件。
進程含有它正在運行的程序,還有棧和堆空間。除此之外,進程還需要記錄數據流的連向,比如標準輸出連到了哪里。這些記錄記在哪里呢?答案就是描述符表。進程用文件描述符表示數據流,所謂的描述符其實就是一個數字。進程會把文件描述符和對應的數據流保存在描述符表中。
描述符表
描述符表的一列是文件描述符號,另一列是它們對應的數據流。雖然名字叫文件描述符,但它們不一定連接硬盤上的某個文件,也可能連接鍵盤、屏幕、文件指針、網絡。
描述符表的前三項是不會變的:0號標準輸入、1號標準輸出、2號標準錯誤。其他項要么為空,要么連接進程打開的數據流。比如程序在打開文件進行讀寫時,就會占用其中一項。描述符表的大小是從0到255號。
創建進程以后,標準輸入連接到鍵盤,標準輸出和標準錯誤連接到屏幕。它會保持這樣的連接,直到有人把它們重定向到了其他地方。
重定向就是替換數據流
標準輸入/輸出/錯誤在描述符表中的位置是固定的,但它們指向的數據流是可以改變的。例如想重定向標準輸出,只需要修改表中1號描述符對應的數據流就OK了。
所有向標準輸出發送數據的函數會先查看描述符表,看1號描述符指向哪條數據流,然后再把數據寫到這條數據流中,printf()函數就是這樣。
進程可以重定向自己
在命令行中可以用“>“和”<"運算符重定向程序。進程也能重定向它們自己,只需修改描述符表。只需要兩步就可以實現:
1.fileno()返回文件描述符號
每打開一個文件,操作系統都會在描述符表中新注冊一項。假設我們打開了log.txt文件:
FILE *my_file = fopen("log.txt","w");
1
操作系統會打開log.txt文件,然后返回一個指向它的指針,操作系統還會遍歷描述符表找空項,把新文件注冊在其中。
int descriptor = fileno(my_file);
1
在失敗時不返回-1的函數很少,fileno()就是其中之一。只要你把打開文件的文件指針傳給fileno(),它就一定會返回描述符編號。
2.dup2()復制數據流
每次打開文件都會使用描述符表中新的一項。但如果你想修改某個已經注冊過的數據流,比如讓1號文件描述符重新指向其他數據流,就可以用dup2()函數來實現,dup2()可以復制數據流,假設我們在3號文件描述符中注冊了log.txt文件指針,下面代碼就可以同時把文件指針連接到1號描述符:
dup2(3,1);
1
雖然log.txt文件只有一個,與它相連的數據流也只有一個,但是數據流(FILE *)同時注冊在文件描述符1和3中。所以標準輸出都會被重定向到文件log.txt中。
我們看一個完整的實例:
#include
1
2
3
4
5
6
7
8
9
10
11
12
13
14
編譯運行:
~/Desktop/MyC$ gcc test4.c -o test4 ~/Desktop/MyC$ ./test4 ~/Desktop/MyC$ tail -f log.txt Hello world,I love you!
1
2
3
4
用管道連接輸入與輸出,符號“|”表示管道(pipe),它能連接一個進程的標準輸出與另一個進程的標準輸入。
如:
~/Desktop/MyC$ ls /usr/include | grep stdio stdio_ext.h stdio.h
1
2
3
ls程序的標準輸出會連接到grep程序的標準輸入。
謝謝閱讀!
任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。