此篇文章主要會帶你介紹 Linux 操做系統,包括 Linux 自己、Linux 如何使用、以及系統調用和 Linux 是如何工做的。程序員
UNIX 是一個交互式系統,用於同時處理多進程和多用戶同時在線。爲何要說 UNIX,那是由於 Linux 是由 UNIX 發展而來的,UNIX 是由程序員設計,它的主要服務對象也是程序員。Linux 繼承了 UNIX 的設計目標。從智能手機到汽車,超級計算機和家用電器,從家用臺式機到企業服務器,Linux 操做系統無處不在。shell
大多數程序員都喜歡讓系統儘可能簡單,優雅並具備一致性。舉個例子,從最底層的角度來說,一個文件應該只是一個字節集合。爲了實現順序存取、隨機存取、按鍵存取、遠程存取只能是妨礙你的工做。相同的,若是命令瀏覽器
ls A*
複製代碼
意味着只列出以 A 爲開頭的全部文件,那麼命令緩存
rm A*
複製代碼
應該會移除全部以 A 爲開頭的文件而不是隻刪除文件名是 A*
的文件。這個特性也是最小吃驚原則(principle of least surprise)
bash
最小吃驚原則一半經常使用於用戶界面和軟件設計。它的原型是:該功能或者特徵應該符合用戶的預期,不該該使用戶感到驚訝和震驚。服務器
一些有經驗的程序員一般但願系統具備較強的功能性和靈活性。設計 Linux 的一個基本目標是每一個應用程序只作一件事情並把他作好。因此編譯器只負責編譯的工做,編譯器不會產生列表,由於有其餘應用比編譯器作的更好。網絡
不少人都不喜歡冗餘,爲何在 cp 就能描述清楚你想幹何時還使用 copy?這徹底是在浪費寶貴的 hacking time
。爲了從文件中提取全部包含字符串 ard
的行,Linux 程序員應該輸入併發
grep ard f
複製代碼
Linux 系統是一種金字塔模型的系統,以下所示socket
應用程序發起系統調用把參數放在寄存器中(有時候放在棧中),併發出 trap
系統陷入指令切換用戶態至內核態。由於不能直接在 C 中編寫 trap 指令,所以 C 提供了一個庫,庫中的函數對應着系統調用。有些函數是使用匯編編寫的,可是可以從 C 中調用。每一個函數首先把參數放在合適的位置而後執行系統調用指令。所以若是你想要執行 read 系統調用的話,C 程序會調用 read 函數庫來執行。這裏順便提一下,是由 POSIX 指定的庫接口而不是系統調用接口。也就是說,POSIX 會告訴一個標準系統應該提供哪些庫過程,它們的參數是什麼,它們必須作什麼以及它們必須返回什麼結果。編輯器
除了操做系統和系統調用庫外,Linux 操做系統還要提供一些標準程序,好比文本編輯器、編譯器、文件操做工具等。直接和用戶打交道的是上面這些應用程序。所以咱們能夠說 Linux 具備三種不一樣的接口:系統調用接口、庫函數接口和應用程序接口
Linux 中的 GUI(Graphical User Interface)
和 UNIX 中的很是類似,這種 GUI 建立一個桌面環境,包括窗口、目標和文件夾、工具欄和文件拖拽功能。一個完整的 GUI 還包括窗口管理器以及各類應用程序。
Linux 上的 GUI 由 X 窗口支持,主要組成部分是 X 服務器、控制鍵盤、鼠標、顯示器等。當在 Linux 上使用圖形界面時,用戶能夠經過鼠標點擊運行程序或者打開文件,經過拖拽將文件進行復制等。
事實上,Linux 操做系統能夠由下面這幾部分構成
引導程序(Bootloader)
:引導程序是管理計算機啓動過程的軟件,對於大多數用戶而言,只是彈出一個屏幕,但其實內部操做系統作了不少事情內核(Kernel)
:內核是操做系統的核心,負責管理 CPU、內存和外圍設備等。初始化系統(Init System)
:這是一個引導用戶空間並負責控制守護程序的子系統。一旦從引導加載程序移交了初始引導,它就是用於管理引導過程的初始化系統。後臺進程(Daemon)
:後臺進程顧名思義就是在後臺運行的程序,好比打印、聲音、調度等,它們能夠在引導過程當中啓動,也能夠在登陸桌面後啓動圖形服務器(Graphical server)
:這是在監視器上顯示圖形的子系統。一般將其稱爲 X 服務器或 X。桌面環境(Desktop environment)
:這是用戶與之實際交互的部分,有不少桌面環境可供選擇,每一個桌面環境都包含內置應用程序,好比文件管理器、Web 瀏覽器、遊戲等應用程序(Applications)
:桌面環境不提供完整的應用程序,就像 Windows 和 macOS 同樣,Linux 提供了成千上萬個能夠輕鬆找到並安裝的高質量軟件。儘管 Linux 應用程序提供了 GUI ,可是大部分程序員仍偏好於使用命令行(command-line interface)
,稱爲shell
。用戶一般在 GUI 中啓動一個 shell 窗口而後就在 shell 窗口下進行工做。
shell 命令行使用速度快、功能更強大、並且易於擴展、而且不會帶來肢體重複性勞損(RSI)
。
下面會介紹一些最簡單的 bash shell。當 shell 啓動時,它首先進行初始化,在屏幕上輸出一個 提示符(prompt)
,一般是一個百分號或者美圓符號,等待用戶輸入
等用戶輸入一個命令後,shell 提取其中的第一個詞,這裏的詞指的是被空格或製表符分隔開的一連串字符。假定這個詞是將要運行程序的程序名,那麼就會搜索這個程序,若是找到了這個程序就會運行它。而後 shell 會將本身掛起直到程序運行完畢,以後再嘗試讀入下一條指令。shell 也是一個普通的用戶程序。它的主要功能就是讀取用戶的輸入和顯示計算的輸出。shell 命令中能夠包含參數,它們做爲字符串傳遞給所調用的程序。好比
cp src dest
複製代碼
會調用 cp 應用程序幷包含兩個參數 src
和 dest
。這個程序會解釋第一個參數是一個已經存在的文件名,而後建立一個該文件的副本,名稱爲 dest。
並非全部的參數都是文件名,好比下面
head -20 file
複製代碼
第一個參數 -20,會告訴 head 應用程序打印文件的前 20 行,而不是默認的 10 行。控制命令操做或者指定可選值的參數稱爲標誌(flag)
,按照慣例標誌應該使用 -
來表示。這個符號是必要的,好比
head 20 file
複製代碼
是一個徹底合法的命令,它會告訴 head 程序輸出文件名爲 20 的文件的前 10 行,而後輸出文件名爲 file 文件的前 10 行。Linux 操做系統能夠接受一個或多個參數。
爲了更容易的指定多個文件名,shell 支持 魔法字符(magic character)
,也被稱爲通配符(wild cards)
。好比,*
能夠匹配一個或者多個可能的字符串
ls *.c
複製代碼
告訴 ls 列舉出全部文件名以 .c
結束的文件。若是同時存在多個文件,則會在後面進行並列。
另外一個通配符是問號,負責匹配任意一個字符。一組在中括號中的字符能夠表示其中任意一個,所以
ls [abc]*
複製代碼
會列舉出全部以 a
、b
或者 c
開頭的文件。
shell 應用程序不必定經過終端進行輸入和輸出。shell 啓動時,就會獲取 標準輸入、標準輸出、標準錯誤文件進行訪問的能力。
標準輸出是從鍵盤輸入的,標準輸出或者標準錯誤是輸出到顯示器的。許多 Linux 程序默認是從標準輸入進行輸入並從標準輸出進行輸出。好比
sort
複製代碼
會調用 sort 程序,會從終端讀取數據(直到用戶輸入 ctrl-d 結束),根據字母順序進行排序,而後將結果輸出到屏幕上。
一般還能夠重定向標準輸入和標準輸出,重定向標準輸入使用 <
後面跟文件名。標準輸出能夠經過一個大於號 >
進行重定向。容許一個命令中重定向標準輸入和輸出。例如命令
sort <in >out
複製代碼
會使 sort 從文件 in 中獲得輸入,並把結果輸出到 out 文件中。因爲標準錯誤沒有重定向,因此錯誤信息會直接打印到屏幕上。從標準輸入讀入,對其進行處理並將其寫入到標準輸出的程序稱爲 過濾器
。
考慮下面由三個分開的命令組成的指令
sort <in >temp;head -30 <temp;rm temp
複製代碼
首先會調用 sort 應用程序,從標準輸入 in 中進行讀取,並經過標準輸出到 temp。當程序運行完畢後,shell 會運行 head ,告訴它打印前 30 行,並在標準輸出(默認爲終端)上打印。最後,temp 臨時文件被刪除。輕輕的,你走了,你揮一揮衣袖,不帶走一片雲彩。
命令行中的第一個程序一般會產生輸出,在上面的例子中,產生的輸出都不 temp 文件接收。然而,Linux 還提供了一個簡單的命令來作這件事,例以下面
sort <in | head -30
複製代碼
上面 |
稱爲豎線符號,它的意思是從 sort 應用程序產生的排序輸出會直接做爲輸入顯示,無需建立、使用和移除臨時文件。由管道符號鏈接的命令集合稱爲管道(pipeline)
。例如以下
grep cxuan *.c | sort | head -30 | tail -5 >f00
複製代碼
對任意以 .t
結尾的文件中包含 cxuan
的行被寫到標準輸出中,而後進行排序。這些內容中的前 30 行被 head 出來並傳給 tail ,它又將最後 5 行傳遞給 foo。這個例子提供了一個管道將多個命令鏈接起來。
能夠把一系列 shell 命令放在一個文件中,而後將此文件做爲輸入來運行。shell 會按照順序對他們進行處理,就像在鍵盤上鍵入命令同樣。包含 shell 命令的文件被稱爲 shell 腳本(shell scripts)
。
推薦一個 shell 命令的學習網站:www.shellscript.sh/
shell 腳本其實也是一段程序,shell 腳本中能夠對變量進行賦值,也包含循環控制語句好比 if、for、while 等,shell 的設計目標是讓其看起來和 C 類似(There is no doubt that C is father)。因爲 shell 也是一個用戶程序,因此用戶能夠選擇不一樣的 shell。
Linux 的命令行也就是 shell,它由大量標準應用程序組成。這些應用程序主要有下面六種
除了這些標準應用程序外,還有其餘應用程序好比 Web 瀏覽器、多媒體播放器、圖片瀏覽器、辦公軟件和遊戲程序等。
咱們在上面的例子中已經見過了幾個 Linux 的應用程序,好比 sort、cp、ls、head,下面咱們再來認識一下其餘 Linux 的應用程序。
咱們先從幾個例子開始講起,好比
cp a b
複製代碼
是將 a 複製一個副本爲 b ,而
mv a b
複製代碼
是將 a 移動到 b ,可是刪除原文件。
上面這兩個命令有一些區別,cp
是將文件進行復制,複製完成後會有兩個文件 a 和 b;而 mv
至關因而文件的移動,移動完成後就再也不有 a 文件。cat
命令能夠把多個文件內容進行鏈接。使用 rm
能夠刪除文件;使用 chmod
能夠容許全部者改變訪問權限;文件目錄的的建立和刪除可使用 mkdir
和 rmdir
命令;使用 ls
能夠查看目錄文件,ls 能夠顯示不少屬性,好比大小、用戶、建立日期等;sort 決定文件的顯示順序
Linux 應用程序還包括過濾器 grep,grep
從標準輸入或者一個或多個輸入文件中提取特定模式的行;sort
將輸入進行排序並輸出到標準輸出;head
提取輸入的前幾行;tail 提取輸入的後面幾行;除此以外的過濾器還有 cut
和 paste
,容許對文本行的剪切和複製;od
將輸入轉換爲 ASCII ;tr
實現字符大小寫轉換;pr
爲格式化打印輸出等。
程序編譯工具使用 gcc
;
make
命令用於自動編譯,這是一個很強大的命令,它用於維護一個大的程序,每每這類程序的源碼由許多文件構成。典型的,有一些是 header files 頭文件
,源文件一般使用 include
指令包含這些文件,make 的做用就是跟蹤哪些文件屬於頭文件,而後安排自動編譯的過程。
下面列出了 POSIX 的標準應用程序
程序 | 應用 |
---|---|
ls | 列出目錄 |
cp | 複製文件 |
head | 顯示文件的前幾行 |
make | 編譯文件生成二進制文件 |
cd | 切換目錄 |
mkdir | 建立目錄 |
chmod | 修改文件訪問權限 |
ps | 列出文件進程 |
pr | 格式化打印 |
rm | 刪除一個文件 |
rmdir | 刪除文件目錄 |
tail | 提取文件最後幾行 |
tr | 字符集轉換 |
grep | 分組 |
cat | 將多個文件連續標準輸出 |
od | 以八進制顯示文件 |
cut | 從文件中剪切 |
paste | 從文件中粘貼 |
在上面咱們看到了 Linux 的總體結構,下面咱們從總體的角度來看一下 Linux 的內核結構
內核直接坐落在硬件上,內核的主要做用就是 I/O 交互、內存管理和控制 CPU 訪問。上圖中還包括了 中斷
和 調度器
,中斷是與設備交互的主要方式。中斷出現時調度器就會發揮做用。這裏的低級代碼中止正在運行的進程,將其狀態保存在內核進程結構中,並啓動驅動程序。進程調度也會發生在內核完成一些操做而且啓動用戶進程的時候。圖中的調度器是 dispatcher。
注意這裏的調度器是
dispatcher
而不是scheduler
,這二者是有區別的scheduler 和 dispatcher 都是和進程調度相關的概念,不一樣的是 scheduler 會從幾個進程中隨意選取一個進程;而 dispatcher 會給 scheduler 選擇的進程分配 CPU。
而後,咱們把內核系統分爲三部分。
從圖中能夠看出 I/O 層次的關係,最高層是一個虛擬文件系統
,也就是說無論文件是來自內存仍是磁盤中,都是通過虛擬文件系統中的。從底層看,全部的驅動都是字符驅動或者塊設備驅動。兩者的主要區別就是是否容許隨機訪問。網絡驅動設備並非一種獨立的驅動設備,它其實是一種字符設備,不過網絡設備的處理方式和字符設備不一樣。
上面的設備驅動程序中,每一個設備類型的內核代碼都不一樣。字符設備有兩種使用方式,有一鍵式
的好比 vi 或者 emacs ,須要每個鍵盤輸入。其餘的好比 shell ,是須要輸入一行按回車鍵將字符串發送給程序進行編輯。
網絡軟件一般是模塊化的,由不一樣的設備和協議來支持。大多數 Linux 系統在內核中包含一個完整的硬件路由器的功能,可是這個不能和外部路由器相比,路由器上面是協議棧
,包括 TCP/IP 協議,協議棧上面是 socket 接口,socket 負責與外部進行通訊,充當了門的做用。
磁盤驅動上面是 I/O 調度器,它負責排序和分配磁盤讀寫操做,以儘量減小磁頭的無用移動。
I/O 右邊的是內存部件,程序被裝載進內存,由 CPU 執行,這裏會涉及到虛擬內存的部件,頁面的換入和換出是如何進行的,壞頁面的替換和常用的頁面會進行緩存。
進程模塊負責進程的建立和終止、進程的調度、Linux 把進程和線程看做是可運行的實體,並使用統一的調度策略來進行調度。
在內核最頂層的是系統調用接口,全部的系統調用都是通過這裏,系統調用會觸發一個 trap,將系統從用戶態轉換爲內核態,而後將控制權移交給上面的內核部件。