Linux架構與文件流

我以下圖爲基礎,說明Linux的架構(architecture)。(該圖參考《Advanced Programming in Unix Environment》)

 

最內層是硬件,最外層是用戶常用的應用,比如說firefox瀏覽器,evolution查看郵件,一個計算流體模型等等。硬件是物質基礎,而應用提供服務。但在兩者之間,還要經過一番周折。

還記得Linux啓動。Linux首先啓動內核 (kernel),內核是一段計算機程序,這個程序直接管理管理硬件,包括CPU、內存空間、硬盤接口、網絡接口等等。所有的計算機操作都要通過內核傳遞給硬件。

 

爲了方便調用內核,Linux將內核的功能接口製作成系統調用(system call)。系統調用看起來就像C語言的函數。你可以在程序中直接調用。Linux系統有兩百多個這樣的系統調用。用戶不需要了解內核的複雜結構,就可以使用內核。系統調用是操作系統的最小功能單位。一個操作系統,以及基於操作系統的應用,都不可能實現超越系統調用的功能。一個系統調用函數就像是漢字的一個筆畫。任何一個漢字都要由基本的筆畫(點、橫、撇等等)構成。我不能臆造筆畫。

在命令行中輸入$man 2 syscalls可以查看所有的系統調用。你也可以通過$man 2 read來查看系統調用read()的說明。在這兩個命令中的2都表示我們要在2類(系統調用類)中查詢 (具體各個類是什麼可以通過$man man看到)。

 

系統調用提供的功能非常基礎,所以使用起來很麻煩。一個簡單的給變量分配內存空間的操作,就需要動用多個系統調用。Linux定義一些庫函數(library routine)來將系統調用組合成某些常用的功能。上面的分配內存的操作,可以定義成一個庫函數(像malloc()這樣的函數)。再比如說,在讀取文件的時候,系統調用要求我們設置好所需要的緩衝。我可以使用Standard IO庫中的讀取函數。這個讀取函數既負責設置緩衝,又負責使用讀取的系統調用函數。使用庫函數對於機器來說並沒有效率上的優勢,但可以把程序員從細節中解救出來。庫函數就像是漢字的偏旁部首,它由筆畫組成,但使用偏旁部首更容易組成字,比如"鐵"。當然,你也完全可以不使用庫函數,而直接調用系統函數,就像“人”字一樣,不用偏旁部首。

(實際上,一個操作系統要稱得上是UNIX系統,必須要擁有一些庫函數,比如ISO C標準庫,POSIX標準等。)

 

shell是一個特殊的應用。很多用戶將它稱爲命令行。shell是一個命令解釋器(interpreter),當我們輸入“ls -l”的時候,它將此字符串解釋爲

  1. 在默認路徑找到該文件(/bin/ls),
  2. 執行該文件,並附帶參數"-l"。

我之前用>表示重新定向,用|表示管道,也是通過shell解釋&或者|的含義。Shell接着通過系統調,用指揮內核,實現具體的重定向或者管道。在沒有圖形界面之前,shell充當了用戶的界面,當用戶要運行某些應用時,通過shell輸入命令,來運行程序。shell是可編程的,它可以執行符合shell語法的文本。這樣的文本叫做shell腳本(script)。可以在架構圖中看到,shell下通系統調用,上通各種應用,同時還有許多自身的小工具可以使用。Shell腳本可以在寥寥數行中,實現複雜的功能。

UNIX的一條哲學是讓每個程序儘量獨立的做好一個小的功能。而shell充當了這些小功能之間的"膠水",讓不同程序能夠以一個清晰的接口(文本流)協同工作,從而增強各個程序的功能。這也是Linux老鳥鼓勵新手多用shell,少用圖形化界面的原因之一。

(shell也有很多種,最常見的是bash, 另外還有sh, csh, tcsh, ksh。它們出現的年代不同,所支持的功能也有差異。)

一個使用bash shell的終端

一個shell對應一個終端 (terminal)。曾經來說,終端是一個硬件設備,用來輸入並顯示輸出。如今,由於圖形化界面的普及,終端往往就像上圖一樣,是一個圖形化的窗口。你可以通過這個窗口輸入或者輸出文本。這個文本直接傳遞給shell進行分析解釋,然後執行。

最後,我們進入一般的應用。應用是一個程序,它可以

  1. 直接調用系統函數
  2. 調用庫函數
  3. 運行shell腳本

這些應用可以由多種語言開發。最常見的是C語言。

 

總結 

Linux利用內核實現軟硬件的對話。

通過系統調用的這個接口,Linux將上層的應用與下層的內核分離,隱藏了底層的複雜性,也提高了上層應用的可移植性。

庫函數利用系統調用創造出模塊化的功能,

Shell則提供了一個用戶界面,並讓我們可以利用shell的語法編寫腳本,以整合程序。



原文地址:http://www.cnblogs.com/vamei/archive/2012/09/19/2692452.html



文本流

文件用於數據的存儲,相當於一個個存儲數據的房子。我們之前說,所謂的數據是0或者1的序列,但嚴格來說,Linux以字節(byte)來作爲數據的單位,也就是說這個序列每八位(bit)爲一個單位(八位二進制對應的十進制範圍爲0到255)。使用ASCII編碼,可以將這樣一個字節轉換成爲字符。所以,在Linux中,我們所說的數據,完全可以用字符表達出來,也就是說文本(text)的形式。

實際上,如果以bit爲單位處理字符的話,機器會更容易讀懂和傳輸,效率會更高。但爲什麼Linux依然以字節爲單位進行處理呢?原因在於,相對於以bit爲單位處理數據,以byte爲單位可以更容易將數據轉化爲字符。相對於枯燥的0和1,字符更容易被人讀懂 (human readable)。然而,並不是所有的數據都是設計來讓人讀懂的,比如可執行文件包含的各種字符對於人來說並沒有什麼意義 (因爲可執行文件是爲了讓機器讀懂的)。但Linux依然以字節爲單位處理所有文件,這是爲了讓所有文件能夠共用一套接口 (virtual file system),從而減少Linux設計的複雜度。

("everything is a file"是通常所流傳的UNIX設計的哲學之一,但Linus對此作出糾正,改爲"everything is a stream of bytes"。)

然而,數據不是在找到了自己的房子(file)之後就永遠的定居下來。它往往要被讀入到內存 (就像是到辦公室上班),或者被傳送到外部設備(好像去酒店休假),或者搬到別的房子中。在這樣的搬遷過程中,數據像是一個個排着隊走路的人流,我們叫它文本流(text stream,或者byte stream)。然而,計算機不同設備之間的連接方法差異很大,從內存到文件的連接像是爬山,從內存到外設像是遊過一條河。爲此,Linux還定義了流 (stream),以此作爲修建連接各處的公路的標準。Stream的好處在於,無論你是從內存到外設,還是從內存到文件,所有的公路都是相同的 (至於公路下面是石頭還是土地,都可以不用操心)。

我們再回味一下“everything is a stream of bytes”這句話。信息包含在文本流中,不斷在計算機的各個組件之間流動,不斷地接受計算機的加工,最終成爲用戶所需要的某種服務。

(說句題外話,如果看過駭客帝國的話,一定會對文本流印象深刻。)

 

標準輸入,標準輸出,標準錯誤與重新定向

當Linux執行一個程序的時候,會自動打開三個流,標準輸入(standard input),標準輸出(standard output),標準錯誤(standard error)。比如說你打開命令行的時候,默認情況下,命令行的標準輸入連接到鍵盤,標準輸出和標準錯誤都連接到屏幕。對於一個程序來說,儘管它總會打開這三個流,但它會根據需要使用,並不是一定要使用。

想象一下敲擊一個

$ls

鍵盤敲擊的文本流("ls\n",\n是回車時輸入的字符,表示換行)命令行 (命令行實際上也是一個程序)。命令行隨後調用/bin/ls得到結果("a.txt"),最後這個輸出的文本流("a.txt")流到屏幕,顯示出來,比如說:

a.txt

假設說我們不想讓文本流流到屏幕,而是流到另一個文件,我們可以採用重新定向(redirect)的機制。

$ls > a.txt

重新定向標準輸出。這裏的>就是提醒命令行,讓它知道我現在想變換文本流的方向了,我們不讓標準輸出輸出到屏幕,而是要到a.txt這個文件 (好像火車軌道換軌)。此時,計算機會新建一個a.txt的文件,並將命令行的標準輸出指向這個文件。

有另一個符號:

$ls >> a.txt

這裏>>的作用也是重新定向標準輸出。如果a.txt已經存在的話,ls產生的文本流會附加在a.txt的結尾,而不會像>那樣每次都新建a.txt。

 

我們下面介紹命令echo:

$echo IamVamei

echo的作用是將文本流導向標準輸出。在這裏,echo的作用就是將IamVamei輸出到屏幕上。如果是

$echo IamVamei > a.txt

a.txt中就會有IamVamei這個文本。

 

我們也可以用<符號來改變標準輸入。比如cat命令,它可以從標準輸入讀入文本流並輸出到標準輸出:

$cat < a.txt

我們將cat標準輸入指向a.txt,文本會從文件流到cat,然後再輸出到屏幕上。當然,我們還可以同時重新定向標準輸出:

$cat < a.txt > b.txt

這樣,a.txt的內容就複製到了b.txt中。

 

我們還可以使用>&來同時重新定向標準輸出和標準錯誤。假設我們並沒有一個目錄void。那麼

$cd void > a.txt

會在屏幕上返回錯誤信息。因爲此時標準錯誤依然指向屏幕。當我們使用:

$cd void >& a.txt

錯誤信息被導向a.txt。

 

如果只想重新定向標準錯誤,可以使用2>:

$cd void 2> a.txt > b.txt

標準錯誤對應的總是2號,所以有以上寫法。標準錯誤輸出到a.txt,標準輸出輸出到b.txt。

 

管道 (pipe)

理解了以上的內容之後,管道的概念就易如反掌。管道可以將一個命令的輸出導向另一個命令的輸入,從而讓兩個(或者更多命令)像流水線一樣連續工作,不斷地處理文本流。在命令行中,我們用|表示管道:

$cat < a.txt | wc 

wc命令代表word count,用於統計文本中的以及字符的總數。a.txt中的文本先流到cat,然後從cat的標準輸出流到wc的標準輸入,從而讓wc知道自己要處理的是a.txt這個字符串。

 

Linux的各個命令實際上高度專業化,並儘量相互獨立。每一個都只專注於一個小的功能。但通過pipe,我們可以將這些功能合在一起,實現一些複雜的目的。


原文地址:http://www.cnblogs.com/vamei/archive/2012/09/14/2683756.html




當文件出現在一個目錄文件中時,我們就把文件接入到文件系統中,我們稱建立一個到文件的硬鏈接(hard link)。一個文件允許出現在多個目錄中,這樣,它就有多個硬鏈接。當硬鏈接的數目(link count)降爲0時,文件會被Linux刪除。所以很多時候,unlink與remove在Linux操作系統中是一個意思。由於軟鏈接(soft link)的廣泛使用(soft link不會影響link count,而且可以跨越文件系統),現在較少手動建立硬連接。

如上討論硬鏈接時說到的,軟鏈接不會影響文件的link count。如果還記得windows系統的快捷方式的話,Linux的軟鏈接(soft link,也叫做symbolic link)就是linux的快捷方式。軟鏈接本質上是一個文件,它的文件類型是symbolic link。在這個文件中,包含有鏈接指向的文件的絕對路徑。當你從這個文件讀取數據時,linux會把你導向所指向的文件,然後從那個文件中讀取(就好像你雙擊快捷方式的效果一樣)。軟鏈接可以方便的在任何地方建立,並指向任何一個絕對路徑。

軟鏈接本身也是一個文件,也可以執行文件所可以進行的操作。當我們對軟鏈接操作時,要注意我們是對軟鏈接本身操作,還是對軟鏈接指向的目標操作。如果是後者,我們就說該操作跟隨鏈接指引(follow the link)




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章