Linux文件系統(tǒng)之重定向的實(shí)現(xiàn)原理詳解
一、再來理解重定向
1.1 輸出重定向效果演示
分析:ls
指令是顯示當(dāng)前目錄下的文件,本質(zhì)就是將當(dāng)前目錄下所有的文件名以字符串的形式寫入到顯示器文件。采用輸出重定向 >
,將原本應(yīng)該寫入顯示器文件的內(nèi)容寫入到了 log.txtx
文件中。
1.2 重定向的原理
在講解重定向原理前,我們需要明確文件描述符的分配規(guī)則,即從0下標(biāo)開始,尋找最小的沒有使用的數(shù)組位置,它的下標(biāo)就是新打開文件的文件描述符。這里沒有使用的意思是該下標(biāo)里面存的是 NULL
,即沒有指向任何一個(gè)文件對(duì)象。下面通過一段代碼來為大家展示重定向的原理。
// mytest.c int main() { close(1); int fd = open(FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0666); if(fd < 0) { perror("open"); return errno; } const char* str = "Hello Linux!\n"; int cnt = 5; while(cnt--) { write(1, str, strlen(str)); } return 0; }
代碼分析:上面這段代碼就完美的展示了重定向的原理。首先調(diào)用 close
系統(tǒng)調(diào)用將 1 號(hào)下標(biāo)對(duì)應(yīng)的文件關(guān)閉,關(guān)閉的意思就是將 1 下標(biāo)里的內(nèi)容置為 NULL
,原本 1 下標(biāo)里面存儲(chǔ)的內(nèi)容是顯示器文件對(duì)象的地址,也就是標(biāo)準(zhǔn)輸出 stdout
,緊接著調(diào)用 open
打開了一個(gè)文件,根據(jù)文件描述符的分配規(guī)則,新打開的這個(gè)文件的文件描述符就是 1,即文件描述符表(file*
的數(shù)組)1 號(hào)下標(biāo)里面存儲(chǔ)的就是新打開的文件對(duì)象的地址。接下來調(diào)用 write
接口,向 1 號(hào)文件描述符中進(jìn)行寫入,本來 1 號(hào)文件描述符對(duì)應(yīng)的是顯示器文件,原本向顯示器文件中寫入的內(nèi)容,此時(shí)就被寫入到新打開的文件中,沒有向顯示器文件中寫入,因此屏幕上就不會(huì)出現(xiàn)字符串,至此整個(gè)重定向的過程就結(jié)束啦。
總結(jié):重定向的本質(zhì)是對(duì)數(shù)組下標(biāo)里面的內(nèi)容進(jìn)行修改。
1.3 dup2
上面介紹了重定向的原理,下面介紹一下實(shí)現(xiàn)重定向的系統(tǒng)調(diào)用 dup2
。
#include <unistd.h> int dup2(int oldfd, int newfd);
dup2
的具體實(shí)現(xiàn)并不是向上面代碼中那樣,先將一個(gè)文件描述符關(guān)閉,然后緊接著再打開一個(gè)文件。dup2
的使用方法是,用戶在調(diào)用 dup2
接口前,正常打開一個(gè)文件,不用將顯示器文件關(guān)閉,此時(shí)新打開文件的文件描述符就是 3。接下來調(diào)用 dup2
,將新打開文件的文件描述符作為 oldfd
,將顯示器文件的文件描述符也就是 1,作為 newfd
。我們知道,文件描述符本質(zhì)上就是數(shù)組下標(biāo),dup2
函數(shù)中執(zhí)行的工作就是將 oldfd
下標(biāo)里存儲(chǔ)的文件對(duì)象地址拷貝到 newfd
下標(biāo)里面,至此重定向工作就完成了。
小Tips:dup2
的函數(shù)形參有一個(gè)誤導(dǎo),我們可能會(huì)覺得新打開文件的描述符是 newfd
,其實(shí)不然,這里的 newfd
是將要被覆蓋的文件描述符,oldfd
是新打開文件的描述符。
int main() { // close(1); int fd = open(FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0666); if(fd < 0) { perror("open"); return errno; } dup2(fd, 1); const char* str = "Hello Linux!\n"; int cnt = 5; while(cnt--) { write(1, str, strlen(str)); } return 0; }
代碼分析:上面就是輸出重定向的實(shí)現(xiàn)原理,追加重定向只需要把 O_TRUNC
替換成 O_APPEND
。
1.4 輸入重定向效果演示
分析:cat
指令本來是從鍵盤文件中獲取輸入然后寫入顯示器文件中,采用輸入重定向 <
后,是從 log.txt
文件中獲取輸入然后寫入顯示器文件中。
1.5 輸入重定向代碼實(shí)現(xiàn)
// 輸入重定向 int main() { int fd = open(FILE_PATH, O_RDONLY); if(fd < 0) { perror("open"); } dup2(fd, 0); char str[1024]; ssize_t ret = read(fd, str, sizeof(str) - 1); if(ret > 0) { str[ret] = '\0'; printf("echo: %s", str); } return 0; }
小Tips:進(jìn)程歷史打開的文件與進(jìn)行的各種重定向關(guān)系都和未來進(jìn)行的程序替換無關(guān),程序替換并不影響文件訪問。進(jìn)程打開文件和何種重定向工作,本質(zhì)上都是進(jìn)程管理的模塊,而程序替換只會(huì)把用戶空間的代碼和數(shù)據(jù)完全被新程序替換,不會(huì)影響到進(jìn)程管理。
二、再來理解標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤
int main() { fprintf(stdout, "Standard output messages\n"); fprintf(stdout, "Standard output messages\n"); fprintf(stdout, "Standard output messages\n"); fprintf(stderr, "Standard error messages\n"); fprintf(stderr, "Standard error messages\n"); fprintf(stderr, "Standard error messages\n"); return 0; }
代碼分析:>
是輸出重定向,也就是對(duì)標(biāo)準(zhǔn)輸出(1號(hào)文件描述符)進(jìn)行重定向。標(biāo)準(zhǔn)錯(cuò)誤對(duì)應(yīng)的2號(hào)文件描述符并沒有進(jìn)行重定向,因此標(biāo)準(zhǔn)錯(cuò)誤消息仍然打印在了屏幕上。
2.1 同時(shí)對(duì)標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤進(jìn)行重定向
./mytest 1>output.txt 2>error.txt
小Tips:這段代碼就是將1號(hào)文件描述符對(duì)應(yīng)的標(biāo)準(zhǔn)輸出文件重定向到 output.txt 文件,將2號(hào)文件描述符對(duì)應(yīng)的標(biāo)準(zhǔn)錯(cuò)誤文件重定向到 error.txt 文件。這樣以來屏幕上就不會(huì)有任何輸出。
2.2 將標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤重定向到同一個(gè)文件
./mytest 1>all.txt 2>&1
小Tips:將標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤都重定向到 all.txt 文件中。
三、再看一切皆文件
所有操作計(jì)算機(jī)的動(dòng)作,都是通過進(jìn)程去執(zhí)行的,所有的訪問文件操作,都是通過進(jìn)程去實(shí)現(xiàn)的,目前所有對(duì)文件的操作都依賴于進(jìn)程。
小Tips:所有的外設(shè)都被抽象成了文件,每個(gè)外設(shè)都有自己的讀寫方法,不同的外設(shè)讀寫方法一定是不同的。但是我們?cè)趯?duì)文件進(jìn)行讀寫操作的時(shí)候,始終調(diào)用的都是 read
和 write
方法,這是因?yàn)椴僮飨到y(tǒng)為我們提供了一個(gè)方法集類型 file_operations
,該結(jié)構(gòu)體里面都是函數(shù)指針類型,指向外設(shè)的各種方法,這就是多態(tài)的雛形。所謂的一切皆文件,就是操作系統(tǒng)幫我們封裝了一層文件對(duì)象,進(jìn)程對(duì)各種外設(shè)的操作,全都變成了對(duì)文件的操作。
sszie_t read(int fd) { task_struct->files->fd_array[fd]->f_op->read(); }
四、結(jié)語
以上就是Linux文件系統(tǒng)之重定向的實(shí)現(xiàn)原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Linux重定向的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
apachetop 實(shí)現(xiàn)實(shí)時(shí)監(jiān)測(cè)web服務(wù)器運(yùn)行情況
這篇文章主要介紹了apachetop 實(shí)現(xiàn)實(shí)時(shí)監(jiān)測(cè)web服務(wù)器運(yùn)行情況的相關(guān)資料,需要的朋友可以參考下2016-10-10解決Ubuntu 16.04下提示boot分區(qū)空間不足的辦法
最近看了看/boot的大小,發(fā)現(xiàn)幾次升級(jí)后,大小不足,所以想擴(kuò)容,一開始還想用磁盤操作,但上網(wǎng)查詢后發(fā)現(xiàn),磁盤操作實(shí)在風(fēng)險(xiǎn)太大,特別是雙系統(tǒng)的Linux,操作又是很麻煩,后來發(fā)現(xiàn)可以刪除多余的舊內(nèi)核來清理/boot,釋放空間。下面來看看詳細(xì)的解決方法吧。2017-02-02Linux?進(jìn)程管理工具之Supervisor安裝配置
這篇文章主要為大家介紹了Linux?進(jìn)程管理工具之Supervisor使用實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05Linux中特殊權(quán)限SUID、SGID與SBIT的深入講解
linux對(duì)文件的權(quán)限管理簡(jiǎn)直是讓人嘆為觀止,所以這篇文章主要給大家介紹了關(guān)于Linux中特殊權(quán)限SUID、SGID與SBIT的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09Ubuntu編譯內(nèi)核模塊,內(nèi)容體現(xiàn)系統(tǒng)日志中
大家好,本篇文章主要講的是Ubuntu編譯內(nèi)核模塊,內(nèi)容體現(xiàn)系統(tǒng)日志中,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Ubuntu18.04安裝Pycharm教程的實(shí)現(xiàn)
這篇文章主要介紹了Ubuntu18.04安裝Pycharm教程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Ubuntu中添加應(yīng)用程序快速啟動(dòng)器的方法
這篇文章主要介紹了Ubuntu中添加應(yīng)用程序快速啟動(dòng)器的方法,需要的朋友可以參考下2014-09-09