天天看點

Linux輸入輸出重定向,我的代碼實證和深度了解

Linux輸入輸出重定向,我的代碼實證和深度了解

事先申明,本文在了解Linux輸入輸出重定向方面,是有點幹貨的。有别于一般泛泛然的講解,内容以源碼為證,講的比較實在。當然,如果你對“輸入輸出重定向”這個概念上都不知道,還是歡迎移步看我的其它文章吧。

Linux的shell指令的進階操作,主要有:

  • 輸出重定向,操作符是:>、>>
  • 輸入重定向,操作符是:<
  • 管道操作,操作符是(|)

為了從原理上說明管道操作,我們首先得了解檔案描述符。關于檔案描述符的背景知識,請參看我發過的筆記《我當年的Linux系統程式設計筆記-檔案描述符》,這裡不再複述。這裡隻對檔案描述符、标準檔案描述符的概念進行一個大緻的講解。

1 檔案描述符

檔案描述符在形式上是一個非負整數。實際上,它是一個索引值,指向核心為每一個程序所維護的該程序打開檔案的記錄表。當程式打開一個現有檔案或者建立一個新檔案時,核心向程序傳回一個檔案描述符。在程式設計中,一些涉及底層的程式編寫往往會圍繞着檔案描述符展開。但是檔案描述符這一概念往往隻适用于UNIX、Linux這樣的作業系統。在windows中,核心記錄應用打開的對象,就是handle句柄,也是一個整數值,兩者有相似之處。

Linux輸入輸出重定向,我的代碼實證和深度了解

在Linux中,在編寫腳本的時候會頻繁使用标準輸入( stdin)、标準輸出( stdout)和标準錯誤( stderr)。通過内容過濾将輸出重定向到檔案是我們平日裡的基本任務之一。檔案描述符是與某個打開的檔案或資料流相關聯的整數。檔案描述符0、 1以及2是系統預留的,相當于每個程序的全局變量,它們被稱為标準檔案描述符。

Linux輸入輸出重定向,我的代碼實證和深度了解

2 Shell 輸入重定向"<"的基本概念

Linux輸入輸出重定向,我的代碼實證和深度了解

指令文法:command < file

對該指令的解釋是:将輸入重定向到 file。

進一步的解釋是:本來需要從鍵盤stdin擷取輸入的指令,會轉移到檔案file讀取内容。

3 Shell 輸入重定向"<"指令的例子

$ cat input.txt

Line1:This is a sample

Line2:123456abc

Line3:Just file!

$ wc -l < input.txt

3 (wc指令統計的行數)

注意:如果指令不能從标準裝置(stdin)讀取資料,這個指令就不能做輸入重定向。舉例如下:

$ cat wantToEcho.txt

Line1:This is wantToEcho file

$ echo < wantToEcho.txt

指令“ echo < wantToEcho.txt”不會顯示任何資料到指令行上。因為echo指令沒有從标準裝置(stdin)讀取資料的能力,是以不會執行成功。

4 代碼實證了解

從程式的觀點出發,輸入重定向指令“command < file”中,Linux管道機制将操作符“<”右邊的file打開後,輸出到stdin。如果command具有從stdin讀取資料的動作,就正好接收處理。不符合這種情況的指令,不可以用到輸入重定向中來。

怎麼證明這個觀點呢?還是下面的代碼"in-redirect.c"驗證最為直接。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_LEN 1024
int main(void)
{
    char read_buf[BUF_LEN +1];
    ssize_t len_read;
    len_read = read(0,read_buf,BUF_LEN);  //這個0,就是stdin

    if ( len_read < 0 )
    {
        perror("perror:file read error ");
        exit(1);
    }

    read_buf[len_read]=0x0;
    printf("read stdin:%s\n",read_buf);
    return 0;
}           

編譯:gcc in-redirect.c -o in-redirect.out

下面是驗證過程:

$ ./in-redirect.out

123456abc789 (此處手工輸入)

read stdin:123456abc789 

$ cat input.txt 下面一行是input.txt檔案中的内容

Line1:This is a sample

$ ./in-redirect.out < input.txt

read stdin:Line1:This is a sample

in-redirect.out這個程式,會從stdin中讀取内容,通過“<”把它重定向成向input.txt中讀資料了。因為有了源碼示例,是以這個對“<”的了解比較通透。

為什麼上面的代碼“read(0,...);”之前,不用先open打開呢?

這是因為“标準檔案描述符”有别于其它“檔案描述符”,它們是程序建立就預設打開着的,不用open。你可以了解為0、1、2這三個檔案描述符是程序的全局變量。既然是全局變量,拿來就用,可以read,也可以write,就不用open了,因為程序在建立之初,就相當于為你open過了。

5 輸入重定向(<)和輸出重定向(>、>>)的差別

Linux輸入輸出重定向,我的代碼實證和深度了解

從系統程式設計的角度來了解,輸出重定向"command > file"就是:command指令輸出資料,向stdout或stderr輸出(write)資料,Linux Shell把這些資料重新定向(open)輸出(write)到file檔案中。也就是說:輸出重定向就是對stdout或stderr進行重定向。

而輸入重定向“command < file”,則是把Linux Shell把檔案打開(open),write到stdio中去,然後command來讀取(read)stdio的資料并進行處理。也就是說:輸入重定向,就是對stdin進行重定向。

6 輸入重定向和輸出重定向混用

其實,隻要符合輸入輸出重定向的文法,内部再符合标準輸出輸出的stdout、stdin、stderr的讀read寫write要求,都可以組合使用,不管指令有多麼長。

比如上面的指令:wc -l < input.txt (統計input.txt的行數),如果我們想把它再輸出到一個計數檔案cout.txt中,可以這樣做

$ cat input.txt

Line1:This is a sample

Line2:123456abc

Line3:Just file!

$ wc -l < input.txt > cout.txt

$ cat cout.txt

3

這兩個指令和執行結果的說明:

wc -l < input.txt > cout.txt :wc指令本來要從stdin中讀取資料,結果被輸入重定向了(<),變成從檔案input.txt中去讀資料了。輸出的結果本來要輸出到stdout螢幕,結果被輸出重定向了(>),變成了輸出到檔案cout.txt中了。

(這裡是虎哥,撸代碼闆子20載,目前文筆尚差,但均是有感而發。技術一般,還需提高。請關注我,看看數位,聊聊軟體,侃侃職場,互相學習,有項目一起發财!)

繼續閱讀