日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 重定向_Unix/Linux编程实践之IO重定向和管道

發布時間:2025/3/19 linux 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 重定向_Unix/Linux编程实践之IO重定向和管道 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

I/O重定向的原理模型

ls > test.file是如何工作的?shell是如何告訴程序把結果輸出到文件,而不是屏幕?
在who | sort > user.file中,shell是如何把一個進程的輸出連接到另一個進程的輸入的?

IO重定向

其實原理就是>操作符是把文件看成任意大小的和結構的變量。
下面兩個實現是等價的,其中前者用c實現,后者用shell實現:

x?=?func_a(func_b(y));??//把func_b的結果作為func_a的輸入

等價于

prog_b?|?prog_a?>?x

標準I/O

標準I/O的定義是什么?
所有的Unix I/O重定向都是基于標準數據流的原理,所有的Unix工具默認都會攜帶三個數據流:

  • 標準輸入,輸出處理的數據流

  • 標準輸出,結果數據流

  • 標準錯誤處理,錯誤消息流

  • 標準數據流

    標準數據流模型

    從上面兩個圖可以看出來,所有的Unix工具都是使用這種數據流模型。
    這三種流的每一種都是一種特別文件描述符fd。

    重定向的是shell

    一般情況下,通過shell來運行一個程序時,該進程的stdin、stdout和stderr都是默認被連接到當前終端上。
    所以用戶的輸入,程序的輸出或者錯誤消息都是顯示到屏幕終端。

    重定向的是shell,而不是程序本身。
    程序僅僅是持續不斷地和文件描述符0、1、2打交道,把fd和指定文件聯系起來的是shell。
    也就是說shell本身并不會把重定向這個動作和指定文件傳遞給程序。

    最低可用文件描述符

    文件描述符是一個數組的索引號。
    每個進程都有其打開的一組文件,這些打開的文件被保存在一個數組里面,fd就是某文件在此數組中的索引號。

    當打開(open)一個文件的時候,內核為此文件安排的fd總是此數組中最低的可用位置的索引。

    最低可用fd原則

    最后,庫函數isatty(fd),可以用來給一個進程判斷一個fd的指向,和系統調用fstat有關。

    重定向的實現

    根據上面說明的模型,可以設想一下如何寫一個程序來實現重定向的功能。
    有很多種實現方法,下面以stdin定向到一個文件為例進行說明。

    close-then-open策略

    close-then-open策略,具體步驟如下:

  • close(0),把標準輸入的連接掛斷

  • fd = open(file_name,O_RDONLY), 和指定的文件建立一個連接,此時最低可用的fd應該是0

  • 重定向策略open-then-close

    open-close-dup-close策略

    open-close-dup-close策略,具體步驟如下:

  • fd = open(file_name,O_RDONLY), 和指定的文件建立一個連接

  • close(0)

  • newfd = dup(fd) ,copy open fd to 0,得到的newfd是0

  • close(fd)

  • dup重定向

    open-dup2-close策略

    把newfd = dup(fd)和close(0)組成成一個單獨的系統調用dup2,newfd=dup2(oldfd,newfd),一般使用的newfd設置為0。

    shell為子進程重定向其輸出

    以who>userlist.file為例子,shell運行who程序,并將who的輸出重定向到userlist.file。其中的原理是什么?

    關鍵之處在于fork和exec的時間間隙。
    fork之后,子進程準備執行exec。
    shell就利用這個時間間隙來完成子進程的輸出重定向工作。

    系統調用exec替換進程中運行的程序,但它不會改變進程的屬性、和進程中所有的連接。
    文件描述符fd(復制了一個連接)、進程的用戶ID、進程的優先級都不會被系統調用exec改變。
    這是因為打開的文件的并不是程序的代碼,也不是數據。fd是進程的一個屬性,故exec不能改變它們。

    也就是文件描述符fd是可以被exec傳遞的,也會從父進程傳遞到子進程。

    shell為子進程重定向其輸出

    具體流程如下:

  • 父進程fork()

  • 子進程繼承了父進程的stdout fd=1

  • 子進程close(1)

  • 子進程fd=create(file,0644),此時最低可用fd=1

  • 子進程exec()


  • 管道pipe

    管道是內核中一個數據隊列,其每一端都連接著一個文件描述符fd,管道有一個讀取端和寫入端。

    pipe又被稱為無名管道,只有共同父進程的進程之間才可以用pipe連接。原因是它沒有“名字”或者說是匿名的,另外的進程看不到它。

    函數原型resutl=pipe(int array[2]),其中array[0]為讀取端的fd,array[1]為寫入端的fd。
    管道的實現隱藏在內核中,進程只能看到兩個文件描述符fd。

    管道

    pipe()和前面open()這些系統調用是類似的,都適用于最低可用fd原則。
    那么一個進程創建一個pipe之后的效果圖是怎樣的?

    一個進程創建pipe

    可以發現一個進程剛創建一個管道成功的之后,一個pipe的兩端都是連著自己的。
    一般而言,很少有進程利用管道向自己發送數據。
    都是把pipe()和fork()結合起來,連接兩個不同的進程。

    使用fork共享管道

    一個進程剛創建一個管道成功的之后,調用fork()。那么子進程就擁有了兩個fd,分別執行該管道的兩端。
    理論上,父子進程可以同時對該管道進行讀寫操作。
    一般是一個讀,一個寫。

    fork共享管道

    docker就是把fork、pipe和exec結合起來使用。

    管道并非文件

    一方面,管道和文件一樣,是不帶任何結構的字節序列,都可以使用read、write等操作。
    另一方面,兩者還是存在不同之處的。

  • 管道的讀取,必須要有進程往管道中寫入數據,否則會產生阻塞

  • 多個讀者可能會引起麻煩,因為管道是一個隊列,讀取之后,數據就不存在了

  • 寫進程會產生阻塞,直到管道有足夠的容量允許你寫入

  • 若讀者在讀取數據,寫操作會失敗

  • 如果兩個進程沒有關聯,使用FIFO聯系。

    如果兩個進程處于不同的主機上面呢?這個時候把管道的思路擴展到套接字socket上。

    pipe和fifo的本質區別

    無名管道不屬于任何文件系統,只存在于內存中,它是無名無形的,但是可以把它看作一種特殊的文件,通過使用普通文件的read(),write()函數對管道進行操作。

    為了使用fifo,LINUX中設立了一個專門的特殊文件系統--管道文件,它存在于文件系統中,任何進程可以在任何時候通過有名管道的路徑和文件名來訪問管道。但是在磁盤上的只是一個節點,而文件的數據則只存在于內存緩沖頁面中,與普通管道一樣。

    fifo是基于VFS,對應的文件類型就是FIFO文件,可以通過mknod命令在磁盤上創建一個FIFO文件。
    注意:這就是fifo與pipe的本質區別,pipe完全就是存在于內存中,在磁盤上毫無痕跡。

    當進程想通過該FIFO來通信時就可以標準的API open打開該文件,然后開始讀寫操作。對于FIFO的讀寫實現,它與pipe是相同的。
    區別在于,FIFO有open這一操作,而pipe是在調用pipe這個系統調用時直接創建了一對文件描述符用于通信。
    并且,FIFO的open操作還有些細致的地方要考慮,例如如果寫者先打開,尚無讀者,那么肯定是不能通信了,所以就需要先去睡眠等待讀者打開該FIFO,反之對讀者亦然。

    參考

    Linux中的pipe與named pipe

    總結

    以上是生活随笔為你收集整理的linux 重定向_Unix/Linux编程实践之IO重定向和管道的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。