1. 程式人生 > >【01】《UNIX高階環境程式設計》全書精華集錦

【01】《UNIX高階環境程式設計》全書精華集錦

1 引子

眾所周知,Linux系列知識極其重要,公司面試、實際開發都需要用到。最近看了一些資料之後,發覺自己很多地方沒有掌握到位,於是開始逐一查閱,順便整理了這個懶人版供大家參考。

每個需要詳細瞭解問題下面需要的資訊都給出了相應的參考連結,有些還配上了實際操作,相信你認真看完本文之後對於UNIX作業系統基礎能有一個更加清晰的認識。

2 正文

(1)什麼是作業系統?什麼是UNIX作業系統?什麼是Linux作業系統?它們之間的關係是怎樣的?

  • 作業系統:控制計算機硬體和軟體資源,對作業進行合理的排程,以供使用者方便使用的一組軟體的集合。
  • UNIX作業系統,是一個強大的多使用者、多工作業系統,支援多種處理器架構,按照作業系統的分類,屬於分時作業系統。
  • Linux,即GNU/Linux,是一套免費使用和自由傳播的類Unix作業系統,是一個基於POSIX和UNIX的多使用者、多工、支援多執行緒和多CPU的作業系統。
  • Linux繼承了Unix以網路為核心的設計思想,它能執行主要的UNIX工具軟體、應用程式和網路協議。

(2)UNIX作業系統有哪些典型的分支?

Linux,Mac OS X,BSD系列與 Solaris

(3)什麼是Shell?內建變數$$、$*、[email protected]、$?、$#的具體含義是什麼?

shell是一個命令語言直譯器,是使用者和UNIX核心直接的介面,它擁有自己內建的shell命令集,shell也能被系統中其他應用程式所呼叫。使用者在提示符下輸入的命令都由shell先解釋然後傳給UNIX核心。

  • $$ 是shell指令碼執行的當前程序ID號
  • $* 是以一個單字串顯示所有向shell指令碼傳遞的引數
  • [email protected] 是傳遞給shell指令碼的所有引數列表
  • $? 顯示最後命令的退出狀態,0表示沒有錯誤,其他表示有錯誤
  • $# 是傳給指令碼的引數個數

(4)常用的Shell命令,如ls、cd、dd、pwd、ps、cp、chown、chmod、mkdir等的具體用法。

  • ls 列出目錄下的檔案

  • cd 改變當前目錄
  • dd 用指定大小的塊拷貝一個檔案,並在拷貝的同時進行指定的轉換(cc已被用來代表CComplier)
  • pwd 檢視當前工作目錄
  • ps顯示系統中當前執行的程序狀態
  • cp 複製檔案
  • chown 更換所有者
  • mkdir 建立一個目錄
  • chmod 改變檔案訪問許可權

(5)什麼是內部命令?什麼是外部命令?它們的區別是什麼?

內部命令在系統啟動時就調入記憶體,是常駐記憶體的,所以執行效率高。
外部命令是系統的軟體功能,使用者需要時才從硬碟中讀入記憶體。

  • 內部命令:內部命令被構建在shell之中。當執行shell命令時,內部命令的執行速度非常快。這是因為沒有其他的程序因為執行這條命令而被建立。比如說,當我們執行“cd”命令時,沒有程序被建立。在執行過程中只是簡單的改變當前的目錄。

  • 外部命令:外部命令並沒有被構建在shell中。這些可執行的外部命令儲存在一個獨立的檔案當中。當一個外部命令被執行時,一個新的程序即被建立同時命令被執行。比如說,當我們執行“cat”(通常被儲存在/usr/bin目錄下)命令時,然後/usr/bin/cat被執行。

(6)什麼是C語言的標頭檔案?有哪些是作業系統提供的標頭檔案?哪些是C語言的標準標頭檔案?

標頭檔案作為一種包含功能函式、資料介面宣告的載體檔案,主要用於儲存程式的宣告。
C語言的標準標頭檔案:ISOC標準定義的標頭檔案
作業系統提供的標頭檔案:POSIX標準定義的標頭檔案

(7)C語言程式的基本結構是怎樣的?編譯器怎樣搜尋標頭檔案?

  • 順序結構,選擇結構,迴圈結構
    1. C語言,使用include指令,包含標頭檔案,但又細分兩種形式:
      1、形式一:#include “file1”
        gcc先在當前目錄(指包含本條#include指令的原始檔所在的目錄)尋找file1,如果找不到,繼續在由-iquote選項(如果有的話)指定的目錄中尋找file1。
         例如,在檔案/usr/include/sys/stat.h中,包含指令#include “types.h”,那麼gcc先在/usr/include/sys目錄下尋找types.h檔案。嗯,在該目錄下,確實存在一個types.h的文 件。現假設我們把這個檔案移動到另一個目錄:mv /usr/include/sys/types.h /bar/foo/,我們在編譯時,可以通過-iquote選項,在不改變stat.h的情況下,正常編譯(當然,通常不建議這樣做):
      gcc -iquote /bar/foo -I/usr/include/sys *.o
      2、形式二:#include
        gcc按照以下順序查詢file2:
      -Idir1 -Idir2 …
      /usr/local/include
      libdir/gcc///include
      /usr//include
      /usr/include
      第 一行中,-Idir1 -Idir2 … 是使用者通過gcc的-I選項指定的目錄。值得一提的是,放在/usr/local/include/下的標頭檔案也會被gcc自動的檢索,這與/usr /local/lib/目錄下的庫處理方式是不一樣的。

(8)怎樣利用gcc編譯原始檔?gcc的-o、-e、-static、-Wall等選項的具體含義是什麼?怎樣使用?

-o 制定目標名稱,預設的時候,gcc 編譯出來的檔案是a.out
-e 使用-E 選項,執行預處理工作
-static 此選項將禁止使用動態庫,所以,編譯出來的東西,一般都很大,也不需要什麼動態連線庫,就可以執行
-Wall 生成所有警告資訊

(9)什麼是動態連結庫?什麼是靜態連結庫?怎樣用靜態連結的方式編譯C程式?

靜態庫是在連結階段被連結的,所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。
有別於靜態庫,動態庫的連結是在程式執行的時候被連結的。所以,即使程式編譯完,庫仍須保留在系統上,以供程式執行時呼叫。
gcc -static

(10)什麼是檔案系統?UNIX的檔案系統有什麼特點?有哪些具體的檔案型別?

檔案系統是作業系統用於明確儲存裝置(常見的是磁碟,也有基於NAND Flash的固態硬碟)或分割槽上的檔案的方法和資料結構;即在儲存裝置上組織檔案的方法。
Unix可以把一個能隨機存取的儲存介質(如:硬碟、軟盤和光碟)上的儲存空間劃分成一致多個區域,每個區域都可以像獨立的物理裝置一樣單獨進行管理和數 據存取,這樣的儲存區域,即是邏輯裝置。在邏輯裝置上按照一定的格式進行劃分,就構成了邏輯檔案系統,簡稱檔案系統。

  1. 普通檔案 這種檔案包含了某種形式的資料,這些資料無論是檔案還是二進位制對於 UNIX 核心而言都是一樣的。對普通檔案內容的解釋有處理該檔案的應用程式進行。
  2. 目錄檔案 目錄檔案包含了其他檔案的名字以及指向與這些檔案有關資訊的指標。對一個目錄檔案具有讀許可權的任一程序都可以讀取該目錄的內容,但是隻有核心才能直接寫目錄檔案。
  3. 塊特殊檔案 這種檔案型別提供對裝置帶緩衝的訪問,每次訪問以固定長度為單位進行。
  4. 字元特殊檔案 這種檔案型別提供對裝置不帶緩衝的訪問,每次訪問長度可變。系統中的所有裝置要麼是字元特殊檔案,要麼是塊特殊檔案。
  5. FIFO 這種型別檔案用於程序間通訊。也稱為命名管道(namedpipe)。
  6. 套接字(socket) 這種檔案型別用於程序間的網路通訊。
  7. 符號連結(symbolic link) 這種檔案型別指向另一個檔案。

(11)什麼是檔案的訪問許可權?使用chmod命令怎樣改變訪問許可權?chmod 0777是什麼意思?

在linux中的每一個檔案或目錄都包含有訪問許可權,這些訪問許可權決定了誰能訪問和如何訪問這些檔案和目錄
chmod [mode] 檔名(其中mode可用二進位制數表示)
u :目錄或者檔案的當前的使用者
g :目錄或者檔案的當前的群組
o :除了目錄或者檔案的當前使用者或群組之外的使用者或者群組
(u) (g) (o)

— = 0
rwx = 7
0777–>-rwx rwx rwx
對所有使用者開放所有許可權

(12)怎樣解讀ls -l 命令顯示的檔案資訊?

ls -al.png

$ ls -l sobsrc. tgz
-rw-r–r– 1 root root 483997 Ju1 l5 17:3l sobsrc. tgz

r代表只讀,w代表寫,x代表可執行,-代表空許可。
注意這裡共有10個位置。第一個字元指定了檔案型別。在通常意義上,一個目錄也是一個檔案。如果第一個字元是橫線,表示是一個非目錄的檔案。如果是d,表示是一個目錄。
table.png

(13)什麼是管道?什麼是檔案重定向?dup()、dup2()函式怎樣使用?

  • 管道:UNIX作業系統程序間通訊的一種方式,一個程序的輸出直接傳遞到另一個程序作為輸入

  • 二者都用來複制開啟的檔案描述符,複製成功後和複製源共享同一個檔案表。

int dup (int filedes);
int dup2 (int filedes, int filedes2);

  • 兩函式的返回值:若成功則返回新的檔案描述符,若出錯則返回-1
    由dup返回的新的檔案描述符一定是當前可用檔案描述符中的最小數值。用dup2則可以用filedes2引數指定新的描述符的數值。如果filedes2已經開啟,則先將其關閉。若filedes等於filedes2,則dup2返回filedes,而不關閉它。

(14)什麼是檔案的靜態屬性和動態屬性(檔案描述符屬性)?在檔案描述符屬性中,哪些是由程序維護的?哪些是由核心維護的?

圖解

理解具體情況,需要了解由核心維護的3個數據結構:

程序級檔案描述符表(file descriptor table)
系統級開啟檔案表(open file table)
檔案系統i-node表(i-node table)
這3個數據結構之間的關係如下圖所示:
inode.png

核心使用三種資料結構表示開啟的檔案,分別是檔案描述符表、檔案表和 V 節點表。
(1) 每個程序在程序表中都有一個記錄項,記錄項中包含有一張開啟檔案描述符表,每個描述符佔用一項。與每個檔案描述符相關聯的是:
(a) 檔案描述符標誌。
(b) 指向一個檔案表項的指標。
(2) 核心為所有開啟檔案維持一張檔案表。每個檔案表項包含:
(a) 檔案狀態標誌(讀、寫、添寫、同步和非阻塞等)。
(b) 當前檔案偏移量。
(c) 指向該檔案 V 節點表項的指標。
(3) 每個開啟檔案(或裝置)都有一個 v 節點(v-node)結構。v 節點包含了檔案型別和對此檔案進行各種操作的函式的指標。v 節點還包含了從磁碟讀取的 i 節點(i-node)的資訊,i 節點資訊包含了檔案的所有者、檔案長度、檔案所在的裝置、指向檔案的實際資料塊在磁碟上的所在位置的指標等。

(15)什麼是會話(Session)、程序組?它們之間有什麼關係?

程序組是一個或多個程序的集合,通常它們與一組作業相關聯,可以接受來自同一終端的各種訊號。每個程序組都有唯一的程序組ID(整數,也可以存放在pid_t型別中)。
會話是一個或多個程序組的集合。
每個程序組都有一個組長程序,組長程序的標識是程序組ID等於其程序ID。程序呼叫setsid函式建立一個新的會話,該程序會變成新會話的會話首程序,該程序也成為一個新程序組的組長程序。如果此呼叫程序已經是一個程序組的組長,則此函式返回出錯。
呼叫getsid函式返回呼叫程序的回話首程序的程序組id。

(16)父程序和子程序之間是什麼關係?怎樣在父子程序之間共享檔案描述符?

由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是:因為一個程序的子程序可以多於一個,沒有一個函式使一個程序可以獲得其所有子程序的程序id。對子程序來說,之所以fork返回0給它,是因為它隨時可以呼叫getpid()來獲取自己的pid;也可以呼叫getppid()來獲取父程序的id。(程序id 0總是由交換程序使用,所以一個子程序的程序id不可能為0 )。
fork之後,作業系統會複製一個與父程序完全相同的子程序,雖說是父子關係,但是在作業系統看來,他們更像兄弟關係,這2個程序共享程式碼空間,但是資料空間是互相獨立的,子程序資料空間中的內容是父程序的完整拷貝,指令指標也完全相同,子程序擁有父程序當前執行到的位置(兩程序的程式計數器pc值相同,也就是說,子程序是從fork返回處開始執行的),但有一點不同,如果fork成功,子程序中fork的返回值是0,父程序中fork的返回值是子程序的程序號,如果fork不成功,父程序會返回錯誤。可以這樣想象,2個程序一直同時執行,而且步調一致,在fork之後,他們分別作不同的工作,也就是分岔了。這也是fork為什麼叫fork的原因
至於那一個最先執行,可能與作業系統排程演算法有關,而且這個問題在實際應用中並不重要,如果需要父子程序協同,可以通過原語的辦法解決。

父子程序共享檔案描述符的條件:在fork之前開啟檔案。

3.寫在最後: