Linux:文件描述符與重定向

目錄

?一、文件描述符

1.文件內核對象?

2.文件描述符分配原則

二、文件重定向

1.重定向的現象

輸出重定向

輸入重定向?

dup2

2.重定向的使用

三、標準輸出和標準錯誤?


繼上篇文章中,我們了解了fd打印的值為文件描述符,那么它還有什么作用呢??

?一、文件描述符

1.文件內核對象?

我們學習了open函數,知道了文件描述符就是一個整數。Linux 進程默認情況下會有?3 個缺省打開的文件描述符,分別是標準輸入 0,?標準輸出 1,?標準錯誤 2。0、1、2 對應的物理設備一般是:鍵盤顯示器顯示器

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

輸入輸出程序:?

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>int main()
{char buf[1024];// 定義一個1024字節的緩沖區ssize_t s = read(0, buf, sizeof(buf));//從標準輸入(stdin)讀取數據到緩沖區bufif(s > 0)// 檢查是否成功讀取到數據{buf[s] = 0; // 手動添加字符串終止符'\0'write(1, buf, strlen(buf));// 將數據寫入標準輸出write(2, buf, strlen(buf));// 將數據寫入標準錯誤//write() 是直接寫入內核,無需手動刷新緩沖區。}return 0;
}

運行后,輸出一個yes,就會再往顯示屏打印兩個yes?

?

write是如何通過fd找到要打印的文件的呢???

重新理解文件描述符表:


站在用戶的角度,對于文件的操作有這些諸如read、write這些系統調用,也有這些系統調用進行了一定的封裝后誕生的C語言庫函數,這些系統調用的內部會在內存中進行一系列操作,當程序運行的時候,進程里有個叫PCB的結構體,進程的PCB中有這么一塊專門的區域名字叫作fd_array[],它的本質是一個指針數組,它會指向一個一個結構體,而每一個結構體中存儲的是關于這個文件的信息,這個結構體叫做struct file,而前面所說的文件描述符fd,本質上就是這個指針數組的下標。系統默認會打開三個文件:標準輸入、輸出和錯誤。比如你調用read或write的時候,系統會根據fd找到對應的file結構體,然后操作對應文件。不過數據讀寫不是直接和硬盤打交道的——因為CPU只能和內存玩,所以讀寫前得把數據先從硬盤加載到內存里的文件緩沖區里,進程才能從中讀寫。不管讀還是寫,都是在內核緩沖區和用戶空間之間倒騰數據,這也就是為什么系統調用看起來像是在內存里搞事情的原因啦。 結論:在應用層對于數據的讀寫,本質上是將內核緩沖區的數據進行來回拷貝。

2.文件描述符分配原則

我們知道因為系統會默認打開三個文件,分別占用0,1,2這三個位置,?那么把前面這幾個關掉呢?

關閉0:?

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>int main()
{close(0);int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);close(fd);return 0;
}

運行結果(關閉2也是一樣的效果):

?

由此可以推測出,文件描述符的分配規則是:尋找最小的,沒有被使用的數據的位置,分配給指定的打開文件?

二、文件重定向

1.重定向的現象

剛剛其實我們已經細微的發現了重定向了,但是現在我們將要學的更加細:

輸出重定向

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>// 重定向
void test()
{close(1);int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);if(fd < 0){perror("open fail\n");exit(1);}printf("fd-> %d\n", fd);printf("stdout->fd: %d\n", stdout->_fileno);fflush(stdout);close(fd);
}int main()
{test();return 0;
}

?運行結果:

?

運行結果是,在屏幕上沒有任何信息,但在log.txt中居然出現了輸出信息。?

當程序通過關閉標準輸出(fd=1)并重新打開一個文件(如log.txt)時,由于文件描述符遵循"用完即丟"的復用規則,新文件會搶占原本屬于標準輸出的1號索引位置。此時所有以1為默認目標的輸出操作(包括printf)都會被悄悄重定向——它們不再往顯示器寫數據,而是像對待普通文件一樣向log.txt寫入內容。這個過程中,Linux內核通過VFS將設備抽象成統一的文件對象,使得無論stdout原本指向的是屏幕還是磁盤文件,最終都表現為對特定文件描述符的操作。這種設計巧妙利用了文件描述符的索引特性,實現了I/O重定向的核心邏輯:系統只認數字標號,不關心具體綁定的物理設備,真正實現了"一切皆文件"的統一管理理念總結:新打開的文件描述符取代了stdout原先的描述符,大家只認fd==1的文件。?

輸入重定向?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>int main()
{close(0);int fd = open("log.txt", O_RDONLY);if (fd < 0){perror("open");return 1;}printf("fd: %d\n", fd);char buf[64];fgets(buf, sizeof buf, stdin);printf("%s", buf);return 0;
}

?

重定向的本質,就是修改特征文件fd的下標內容。上層的fd不變,變化的是底層fd指向的內容,也就是所謂文件描述符級別的數組內容的拷貝。那這樣的寫法還是太奇怪了,每次都要把一個文件關閉再打開一個新的文件,作為系統理應給操作者提供這樣替換文件描述符的系統調用,事實上也確實提供了這樣的系統調用。?

dup2

SYNOPSIS#include <unistd.h>int dup(int oldfd);int dup2(int oldfd, int newfd);
*  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
*  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.

簡單來說,就是用oldfd去替換newfd,保留下來的是oldfd,那么上面的代碼就可以被改良成這樣:

void redir2()
{int fd = open("log.txt", O_CREAT | O_WRONLY | O_APPEND, 0666);if(fd < 0){perror("open fail\n");exit(1);}dup2(fd, 1);printf("fd-> %d\n", fd);printf("stdout->fd: %d\n", stdout->_fileno);fflush(stdout);close(fd);
}

運行結果:?

?

fd->3,fd也沒有變化,但是就是沒有往顯示屏上打印,依舊是往文件里打印的。也就是說,不需要你去關閉一個文件秒速符,而是用一個文件描述符暫時的代替另外一個文件描述符,這樣不僅更加準確,而且更加明了。

要輸出的文件描述符是 1,而要重定向的目標文件描述符是 fd (echo “hello” > log.txt),dup2 應該怎么傳參 —— dup2(1, fd) || dup2(fd, 1) ??

*  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
*  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.

很明顯依靠函數原型,我們就能認為 dup2(1, fd),因為 1 是先打開的,而 fd 是后打開的.可實際上并不是這樣的,文檔中說 newfd 是 oldfd 的一份拷貝,這里拷貝的是文件描述符對應數組下標的內容,所以數組內容最終應該和 oldfd 一致。換而言之,這里就是想把讓 1 不要指向顯示器了,而指向 log.txt,fd 也指向 log.txt。所以這里的 oldfd 對應 fd,newfd 對應 1,所以應該是 dup2(fd, 1)。

oldfd copy to newfd -> 最后要和誰一樣??oldfd

假設輸出重定向:顯示器(1) -> log.txt(3)。應該是 dup2(1, 3);,還是dup2(3, 1);??

dup2(3, 1);

3 的內容 copy 到 1 里面 -> 最終和 3 一致

2.重定向的使用

?重定向其實并不陌生,在之前的學習中已經用過重定向,只是那是還沒有建立起來一個基礎的概念,先看下面的指令演示:

[root@iZbp1157ft1ib0ydj8jqtzZ test]# echo "hello linux" > log.txt
[root@iZbp1157ft1ib0ydj8jqtzZ test]# cat log.txt
hello linux

這段指令的含義就是,把hello linux重定向到log.txt中,其實這樣的操作符還有下面的這幾種,一一進行介紹

>:這個操作符表示的是輸出重定向,意思就是把內容輸出到某個文件中,有些類似于以w的方式打開一個文件并進行寫入。

>>:這個操作符表示的是追加重定向,意思就是把內容追加輸出到某個文件中,有些類似于append的方式進行寫入。

<:這個操作符表示的是輸入重定向,表示把原來的內容輸入輸入到某個文件中,相當于是替換了標準輸入流的文件。

三、標準輸出和標準錯誤?

前面的知識已經足以理解為什么要有標準輸入和標準輸出,但是還有一個問題有待解決,標準錯誤的意義是什么呢?難道標準輸出的信息還不夠嗎?

答案是確實不夠,在對于大型項目的時候,會有很多的輸出信息,這些輸出信息有些是正常信息,有些是異常信息,而對于開發者來說他們需要的是錯誤信息,因此對于如何獲取錯誤信息就顯得至關重要,于是標準錯誤流信息就誕生了,對于正常來說可能沒有太多的感覺,但是實際上,沒有感覺的原因是因為標準錯誤和標準輸出的文件對象都是顯示器,而實際上這是可以被替換的,基于這個原理可以做出下面的測試代碼:

int main()
{printf("this is normal message\n");perror("this is error message\n");return 0;
}

?運行和操作結果:

[root@iZbp1157ft1ib0ydj8jqtzZ test]# ./test 1>out.txt 2>error.txt
[root@iZbp1157ft1ib0ydj8jqtzZ test]# cat out.txt
this is normal message
[root@iZbp1157ft1ib0ydj8jqtzZ test]# cat error.txt
this is error message
: Success

利用上面的原理可以寫出這樣的測試代碼,把正確信息存儲到一個文件中,把錯誤信息存儲到另外一個文件中,這樣就能知道哪里是錯誤哪里是正確了。

1>&2意思是把標準輸出重定向到標準錯誤。

2>&1意思是把標準錯誤輸出重定向到標準輸出。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72665.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72665.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72665.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

白盒測試(3):PCB阻抗測試方法

PCB阻抗測試是確保信號完整性的關鍵&#xff0c;通過測量走線的特性阻抗&#xff0c;驗證其是否符合設計目標。常用方法包括時域反射法&#xff08;TDR&#xff09;、網絡分析儀法和仿真軟件法。TDR通過分析反射信號定位阻抗異常&#xff0c;網絡分析儀通過S參數計算阻抗&#…

CentOS 7 安裝Nginx-1.26.3

無論安裝啥工具、首先認準了就是官網。Nginx Nginx官網下載安裝包 Windows下載&#xff1a; http://nginx.org/download/nginx-1.26.3.zipLinxu下載 wget http://nginx.org/download/nginx-1.26.3.tar.gzLinux安裝Nginx-1.26.3 安裝之前先安裝Nginx依賴包、自行選擇 yum -y i…

筆記:如何使用XAML Styler以及在不同的開發環境中使用一致

一、目的&#xff1a;分享如何使用XAML Styler以及在不同的開發環境中使用一致 XAML Styler 是一個 Visual Studio 擴展&#xff0c;用于自動格式化和整理 XAML 文件。它可以幫助開發者保持一致的代碼風格&#xff0c;提高代碼的可讀性和可維護性。以下是如何在 Visual Studio …

分布式存儲學習——HBase概述

1.1 HBase概述 1.1.1 理解大數據背景 1.1.2 HBase是什么 1.1.3 HBase與Hadoop的關系 1.1.4 HBase的核心功能模塊 1.1.5 HBase的應用場景和經典案例 1.1.6 小結 本文參考于學校《HBase應用于開發》教材 1.1 HBase概述 本節將介紹大數據背景和HBase的基本概念&#xff0c…

交叉編譯openssl及curl

操作環境&#xff1a;Ubuntu20.04 IDE工具&#xff1a;Clion2020.2 curl下載地址&#xff1a;https://curl.se/download/ openssl下載地址&#xff1a;https://openssl-library.org/source/old/index.html 直接交叉編譯curl會報錯找不到openssl&#xff0c;所以需要先交叉編…

MDM 如何徹底改變醫療設備的遠程管理

在現代醫療行業迅速發展的格局中&#xff0c;醫院和診所越來越依賴諸如醫療平板和移動工作站等移動設備。這些設備在提高工作效率和提供卓越的患者護理方面發揮著關鍵作用。然而&#xff0c;隨著它們的廣泛使用&#xff0c;也帶來了一系列挑戰&#xff0c;例如在不同地點確保數…

零基礎C語言學習日志22(自定義類型:聯合和枚舉)

目錄 聯合體 聯合體類型的聲明 聯合體的特點 相同成員聯合體和結構體的對比 聯合體大小的計算 例子 枚舉類型 枚舉類型的聲明 枚舉類型的優點 枚舉類型的使用 聯合體 聯合體類型的聲明 像結構體一樣&#xff0c;聯合體也是由一個或者多個成員構成&#xff0c;這些成…

天津大學02-深度解讀DeepSeek:部署、使用、安全【文末附下載鏈接】

大模型風險與不當用例——價值觀錯位 大模型與人類價值觀、期望之間的不一致而導致的安全問題&#xff0c;包含&#xff1a;? 社會偏見&#xff08;Social Bias&#xff09;LLM在生成文本時強化對特定社會群體的刻板印象&#xff0c;例如將穆斯林與恐怖主義關聯&#xff0c;或…

[C語言日寄] 字符串操作函數的使用及其拓展

【作者主頁】siy2333 【專欄介紹】?c語言日寄?&#xff1a;這是一個專注于C語言刷題的專欄&#xff0c;精選題目&#xff0c;搭配詳細題解、拓展算法。從基礎語法到復雜算法&#xff0c;題目涉及的知識點全面覆蓋&#xff0c;助力你系統提升。無論你是初學者&#xff0c;還是…

Qt 進度條與多線程應用、基于 Qt 的文件復制工具開發

練習1&#xff1a;Qt 進度條與多線程應用 題目描述 開發一個基于 Qt 的應用程序&#xff0c;該應用程序包含一個水平進度條&#xff08;QSlider&#xff09;&#xff0c;并且需要通過多線程來更新進度條的值。請根據以下要求完成代碼&#xff1a; 界面設計&#xff1a; 使用 QS…

Gartner:數據安全平臺DSP提升數據流轉及使用安全

2025 年 1 月 7 日&#xff0c;Gartner 發布“China Context&#xff1a;Market Guide for Data Security Platforms”&#xff08;《數據安全平臺市場指南——中國篇》&#xff0c;以下簡稱指南&#xff09;&#xff0c;報告主要聚焦中國數據安全平臺&#xff08;Data Securit…

道可云人工智能每日資訊|《奇遇三星堆》VR沉浸探索展(淮安站)開展

道可云元宇宙每日簡報&#xff08;2025年3月5日&#xff09;訊&#xff0c;今日元宇宙新鮮事有&#xff1a; 《奇遇三星堆》VR沉浸探索展&#xff08;淮安站&#xff09;開展 近日&#xff0c;《奇遇三星堆》VR沉浸探索展&#xff08;淮安站&#xff09;開展。該展將三星堆文…

Spring AI Alibaba + Ollama:國產大模型DeepSeek LLM的低成本AI應用開發認知

寫在前面 官方文檔很詳細&#xff0c;有開發需求可以直接看文檔https://java2ai.com/docs/1.0.0-M5.1/get-started/博文內容為一個開發Demo&#xff0c;以及API簡單認知理解不足小伙伴幫忙指正 &#x1f603;,生活加油 我看遠山&#xff0c;遠山悲憫 持續分享技術干貨&#xf…

解決:Word 保存文檔失敗,重啟電腦后,Word 在試圖打開文件時遇到錯誤

殺千刀的微軟&#xff0c;設計的 Word 是個幾把&#xff0c;用 LaTex 寫完公式&#xff0c;然后保存&#xff0c;卡的飛起 我看文檔卡了很久&#xff0c;就關閉文檔&#xff0c;然后 TMD 腦抽了重啟電腦 重啟之后&#xff0c;文檔打不開了&#xff0c;顯示 殺千刀的&#xff…

掌握高效大模型任務流搭建術(二):鏈式流程如何賦能 AI 處理能力提升

前言&#xff1a; 在上一篇文章中&#xff0c;我們初步探索了 LangChain 的基礎鏈式操作——LLMChain。它巧妙地將大語言模型&#xff08;LLM&#xff09;與提示模板&#xff08;Prompt Template&#xff09;相結合&#xff0c;為模型交互邏輯的封裝提供了一種簡潔而高效的方式…

虛擬卡 WildCard (野卡) 保姆級開卡教程

本文首發于只抄博客&#xff0c;歡迎點擊原文鏈接了解更多內容。 前言 本篇教程為 WildCard 的介紹以及開卡教學&#xff0c;要了解不同平臺&#xff08;Grok、Talkatone 等&#xff09;的訂閱方式請移步《訂閱教程》分類 當我們想要充值國外平臺會員時&#xff0c;一般都需要使…

計算機數據庫三級刷題總結(博主89分已過,總結的內容分享)

計算機數據庫三級刷題總結&#xff08;博主89分已過&#xff0c;總結的內容分享&#xff09; 文章目錄 計算機數據庫三級刷題總結&#xff08;博主89分已過&#xff0c;總結的內容分享&#xff09;一、 數據庫設計階段二、事務相關三、數據庫設計順序四、數據庫三級模式與二層映…

記錄一些面試遇到的問題

重載和重寫的區別 重載是overload&#xff0c;覆蓋是override 重載屬于編譯時多態&#xff0c;覆蓋屬于運行時多態 運行時多態和編譯時多態 運行時多態指的是在運行的時候才知道要調用哪一個函數&#xff0c;編譯時多態是指在編譯的時候就知道調用哪一個函數。 運行時多態…

HBuilder X 使用 TortoiseSVN 設置快捷鍵方法

HBuilder X 使用 TortoiseSVN 設置快捷鍵方法 單文件&#xff1a;(上鎖&#xff0c;解鎖&#xff0c;提交&#xff0c;更新) 安裝好 TortoiseSVN &#xff0c;或者 按圖操作&#xff1a; 1&#xff0c;工具欄中 【自定義快捷鍵】 2&#xff0c;點擊 默認的快捷鍵設置&…

JmeterHttp請求頭管理出現Unsupported Media Type問題解決

JmeterHttp請求頭管理出現Unsupported Media Type問題解決 大多數的app與pc端壓測的時候都會出現這種情況 當我們在jemter測試當中當中遇見Unsupported Media Type&#xff0c;有一種可能就是我們請求的網頁的content-Type的類型與我們測試的時候的類型不一致 解決方法 可以添…