’和‘" />
    1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Shell:管道與重定向

        2020-12-11 02:52

        轉(zhuǎn)自:TOMORROW

        鏈接:https://reurl.cc/A8vpQE

        對shell有一定了解的人都知道,管道和重定向是 Linux 中非常實(shí)用的 IPC 機(jī)制。


        在shell中,我們通常使用符合‘|’來表示管道,符號‘>’和‘<’表示重定向。


        那么管道和重定向的真實(shí)含義(定義)又是什么呢?

        管道

        管道的定義

        管道就是一個進(jìn)程與另一個進(jìn)程之間通信的通道,它通常是用作把一個進(jìn)程的輸出通過管道連接到另一個進(jìn)程的輸入。


        它是半雙工運(yùn)作的,想要同時雙向傳輸需要使用兩個管道。


        管道又可以分為匿名管道和命名管道,而shell中使用到的是匿名管道,所以本文僅描述匿名管道。


        例如命令ls | grep main.c,使用了管道來連接了兩條命令來執(zhí)行,能夠快速地讓我們知道當(dāng)前目錄下是否有 main.c 文件。


        管道的本質(zhì)是內(nèi)存中的緩沖區(qū),可以看作是打開到內(nèi)存中的文件。


        所以需要使用兩個文件描述符來索引它,一個表示讀端,一個表示寫端。


        并且規(guī)定,數(shù)據(jù)只能從讀端讀取、只能往寫端寫入。


        創(chuàng)建管道

        使用函數(shù)pipe()可以創(chuàng)建匿名管道,需要包含頭文件 unistd.h,示例代碼:

        int fd[2];
        pipe(fd);

        首先創(chuàng)建一個 2 個元素的整型數(shù)組,然后將該數(shù)組作為pipe()的參數(shù),pipe()執(zhí)行成功后,數(shù)組元素 fd[0]的值就會變成所創(chuàng)建的管道的讀端的文件描述符,fd[1]就會變成寫端的文件描述符。


        至此管道就算創(chuàng)建成功了。


        把管道作為標(biāo)準(zhǔn)輸入輸出

        管道創(chuàng)建成功后,就可以直接使用 read()和 write()函數(shù)對管道進(jìn)行數(shù)據(jù)的讀寫。


        而因?yàn)閟hell中都是使用標(biāo)準(zhǔn)輸入輸出對管道進(jìn)行讀寫的,例如ls | grep main.c就是將 ls 的標(biāo)準(zhǔn)輸出寫到了管道寫端,而 grep 的標(biāo)準(zhǔn)輸入則從管道讀端讀取,所以本文也只描述此方法。


        示例代碼如下:

        int fd[2];
        pipe(fd);
        pid=fork();

        if(0==pid) //execute next command in child process
        {
        dup2(fd[0],0);//redirect standard input to pipe(read)
        close(fd[0]);
        close(fd[1]);

        if(0!=execvp(cmd0[0],cmd0))
        printf("No such command!\n");
        exit(EXIT_SUCCESS);
        }
        else //execute current command in current process
        {
        dup2(fd[1],1);//redirect standard output to pipe(write)
        close(fd[0]);
        close(fd[1]);

        if(0!=execvp(cmd1[0],cmd1))
        printf("No such command!\n");

        exit(EXIT_SUCCESS);
        }
        • 首先是創(chuàng)建一個管道,然后創(chuàng)建子進(jìn)程,子進(jìn)程會繼承這一個管道,也就保證了父進(jìn)程與子進(jìn)程操作的是同一個管道(管道的繼承與普通變量不同)。


          如果我們希望在子進(jìn)程中執(zhí)行管道的讀端的程序例如ls | grep main.c中的grep main.c;在父進(jìn)程中執(zhí)行管道的寫端的程序,例如ls | grep main.c中的ls。

        • 在子進(jìn)程中,先調(diào)用dup2(fd[0],0);此函數(shù)就是將標(biāo)準(zhǔn)輸入的文件描述符 0,指向了管道的讀端。


        文件描述符,本質(zhì)是非負(fù)整數(shù),通常是小整數(shù);它是一個索引,通過該索引可以找到對應(yīng)的文件。


        例如,標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯誤的文件描述符默認(rèn)是 0、1、2 。當(dāng)進(jìn)程需要從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù)時,就會通過 0 索引找到標(biāo)準(zhǔn)輸入所對應(yīng)的內(nèi)存緩沖區(qū)來讀取數(shù)據(jù)。


        • 假設(shè)此時管道讀端的文件描述符為 3、寫端文件描述符為 4 。

        • 調(diào)用dup2(fd[0],0),實(shí)際上就是將文件描述符 3 指向的文件表項(xiàng)賦值給了文件描述符 0,而文件描述符 0 正是進(jìn)程默認(rèn)的標(biāo)準(zhǔn)輸入。


          所以此時,當(dāng)進(jìn)程需要從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)時,進(jìn)程就會通過文件描述符 0 來找到管道讀端所對應(yīng)內(nèi)存緩沖區(qū)。

        • 從而實(shí)現(xiàn)了通過標(biāo)準(zhǔn)輸入來讀取管道的數(shù)據(jù),也可以說是,將管道的讀端重定向到了標(biāo)準(zhǔn)輸入。管道的寫端與標(biāo)準(zhǔn)輸入的關(guān)系也與此類似,此處不再贅述。

        • 調(diào)用dup2(fd[0],0)之后還需要調(diào)用close()函數(shù)將管道原有的文件描述符關(guān)閉,關(guān)閉的意思是文件描述符 3 和 4 不再索引到管道或者其他文件,也就是說此時使用 read 函數(shù)從文件描述符 3 中是讀取不到管道的數(shù)據(jù)的了,并不是說關(guān)閉管道的意思。

        • 完成管道的設(shè)置之后,就可以通過 exec 族函數(shù)來執(zhí)行外部命令了。


          需要注意的是,調(diào)用 exec 族函數(shù)并不會把管道這種 IPC 資源覆蓋或者重新初始化。

        文件重定向

        文件重定向其實(shí)與上面管道重定向到標(biāo)準(zhǔn)輸入輸出很類似,甚至可以直接采用上面所說的方法來實(shí)現(xiàn)。但是此處將講述一種更加簡潔的方法實(shí)現(xiàn)。


        實(shí)例代碼如下:

        char fileName[20]="out.txt";
        freopen(fileName,"w",stdout);//redirect stdout to fileName

        以上兩行簡單的代碼就實(shí)現(xiàn)了,將該進(jìn)程的標(biāo)準(zhǔn)輸出重定向到了文件 out.txt ,甚至一行就可以實(shí)現(xiàn)。


        執(zhí)行以上代碼后,當(dāng)前進(jìn)程的所有標(biāo)準(zhǔn)輸出,也就是 printf()之類的輸出全都會被寫到文件 out.txt,顯示屏將不會有輸出。


        而將進(jìn)程的標(biāo)準(zhǔn)輸入重定向到文件 in.txt 的代碼如下:

        char fileName[20]="in.txt";
        freopen(fileName,"r",stdin);//redirect stdin to fileName

        其中的核心函數(shù)就是freopen()



        良許個人微信


        添加良許個人微信即送3套程序員必讀資料


        → 精選技術(shù)資料共享

        → 高手如云交流社群





        本公眾號全部博文已整理成一個目錄,請?jiān)诠娞柪锘貜?fù)「m」獲?。?/span>

        推薦閱讀:

        程序猿的MacBook M1使用體驗(yàn)

        2020 年最漂亮的 Linux 發(fā)行版

        推薦四款可視化工具,解決 99% 的可視化大屏需求


        5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹莓派,等等。在公眾號內(nèi)回復(fù)「1024」,即可免費(fèi)獲?。?!


        瀏覽 28
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            豆奶狼友视频在线长毛片 | 免费一看一级毛片少妇丰满2 | 激情偷乱人伦小说视频在线 | 男女差差网站 | 亚欧性爱 | 欧美18在线 | 日本水蜜桃身体乳正品推荐 | 影音先锋国产乱伦 | av你懂得| 国产精品一aV一麻夜夜嗨 |