Linux不權威總結

Linux不權威總結

歡迎閱讀

本文主要是從Linux入手,對常用的操作系統知識進行梳理。長篇大論令人生厭,所以本文的一個原則就是聚焦關鍵點,淺嘗輒止,以免誤人子弟,同時也會盡量附上各種詳盡的資料以備感興趣的同學深入了解

Linux簡史

計算機的發明

  • 各大廠家各自制造機器,市場充斥著各種大型機(IBM GE HP)和小型機(Intex).
  • 各個廠家從硬件到軟件(主要是操作系統)維護自己的產品.

Unix誕生

  • 最早的大型機只能服務數十人,于是Bell實驗室跟GE MIT合作啟動MULTICS計劃,旨在開發一個能夠服務上百人的多用戶,多任務,多層級操作系統,卒,但該項目培養了大批優秀的計算機人才
  • Ken Thompson為了玩一款<星際旅行>的游戲,反MULTICS其道而行,力求簡潔實用,誕生了Unix
  • 后續Thompson被匯編語言折騰受不了,發明了c語言,重寫了Unix內核(1970)
  • 由于全新的Unix易于開發移植(得益于c語言),同時功能強大,所以迅速發展,各大廠商也開始兼容Unix,并誕生了POSIX,規范OS提供的編程接口
  • AT&T禁止Unix傳播,Unix開始內戰,互不兼容,各自為戰,一發不可收拾的出現各種變種
  • 此時Intel為各個中小計算機公司生產通用CPU,然后微軟為該體系架構生產通用的操作系統,自此,win-tel體系建立,在Unix內亂之際瘋狂生長
  • Berkeley發布FreeBSD

GNU (GNU's not Unix)

  • Unix的封閉之路使多數人深惡痛絕,Stallman發起自由軟件計劃
  • GPL授權誕生,確定了開源軟件服務化的商業空間
  • GNU計劃開發兼容Unix的操作系統,但是為了先易后難,從應用軟件下手
  • 從免費的編譯器,編輯器,公共庫,腳本工具著手,于是gcc emacs glibc bash...等一大批優秀的開源軟件誕生

Linux誕生

  • Linus Torvalds(芬蘭大學生)在一個教授開發的Unix簡易教學版minix上學習,但由于教授不愿意繼續開發,他便醞釀自己的操作系統
  • Linus發布了自己寫的"小玩意兒",吸引了大量黑客的興趣
  • 為了效率Linus主要開發內核,而將源碼免費開放,所有人協同開發,統一整合
  • 開源,分布式開發,虛擬團隊,快速迭代...這些令人興奮的事件都拉開了序幕
  • Linux正式確定,同時支持移植386小型家用機
  • 廠商開始支持Linux,由于Linux使用gcc,bash等很多GNU計劃的工具,GNU也順理成章的采用Linux,填補了開源內核這一空白,Stallman認為Linux其實應該是GNU/Linux

內核版本 & 發布版本
linux的內核版本號形如2.6.18-92.e15,依次為主版本.次版本.發布版本-修改版本。主、次版本號為奇數的話為內核開發版本,一般是用來測試新功能,內核工程師開發使用的;主、次版本號為偶數則為穩定版本

發布版本distributions,是指各個linux開發商發布的版本,比如CentOS、RedHat。這些開發商都是基于相同的linux內核,不同的是他們會基于此提供不同的服務、工具,比如包安裝、系統管理等

換行和回車

  1. 在早期輸出設備是一種叫做電傳打字機的設備,該設備能夠0.1s打一個字
  2. 但當需要換行的時候,該設備需要0.2秒,兩個動作,換行,同時返回行首
  3. 正好是兩個字符的時間,所有當時為了省事,直接在行尾設置了兩個特殊字符,給設備換行的時間CR 回車 LF 換行
  4. 后來使用電子屏后,一些系統為了節省字符(unix linux)就只有一個LF(\n),mac則只有一個CR(\r),win則兩個都做了保留
  5. 所以如果把win的文件在linux下打開,則會在每行多看見一個^M字符(win的回車),可以使用unix2dos或者dos2unix進行轉換

計算機硬件組成

硬件基本架構

現代計算機基本都是馮·諾依曼結構,即由核心運算器、程序控制器、內存、輸入設備、輸出設備組成。

image

CPU包括核心運算器(ALU)和程序控制器(PC),通過其提供的一系列cpu指令來提供包括數學運算、數據讀取、數據寫入,以及應該運行哪條指令等服務,是計算機的‘心臟’

主存儲器,也就是內存,服務CPU的數據讀取和寫入,與I/O設備數據加載

I/O設備,則各種各種,常見如鼠標、鍵盤、顯示器、USB、磁盤、網卡等,負責從真實世界讀取數據和以各種形式數據數據

這些設備通過總線(PCI)通信,總線同一時間只能廣播一條指令

CPU

中央處理單元,可以說是人類智慧的集中體現。它的模型被抽象的很簡單,讀取一條cpu指令,翻譯指令,然后執行(可能為數學運算、讀取數據、寫入數據或者指定下一條指令),循環往復,直到關機

CPU指令
cpu指令很簡單就是一系列的0、1序列,cpu從寄存器中讀取到這些0、1序列后,執行相應的操作。我們編寫的程序最終都要翻譯成cpu指令。不同的機器cpu實現不同,其指令集也會有所不同,所以編譯好的可執行程序一般不能直接在不同的機器上運行

cpu的指令歷史上有兩條路線,精簡指令集(CISC)復雜指令集(RISC),他們的主要區別是CISC認為cpu常用的指令并不多,不需要因為少數不常用的操作來增加cpu的復雜度,只需要一個少量的簡單指令集合即可,既可以降低cpu的復雜度,也方便對指令進行優化;RISC則是提供功能強大,但是更耗cpu周期的指令來方便cpu的使用。目前兩者已經逐漸融合

CPU型號
不同廠家生產的CPU具有不同構造和指令集,最初計算機的CPU是需要各個公司自己設計生產的。后來Intel公司設計生產了通用cpu,逐漸成為市場標準

由于Intel生產的cpu最初型號是8086、80286、i386、i486等,人們習慣稱Intel系列cpu為x86,根據cpu支持的位數不同,又分為x86-32和x86-64。此外還有IBM處理器和arm處理器

CPU數量
服務器的物理CPU是可以多核的,所以 邏輯cpu數 = 物理cpu * 核數。可以通過uptime top 等工具查看系統的平均負載,了解服務器的運行情況

如果有4個邏輯cpu,top顯示負載在4及以下,則說明系統相對正常,如果長期在4以上則說明服務器壓力過大(負載值同一時間段內運行的進程數,所以是會比cpu數大的)

Linux文件系統

一切皆文件
linux一個非常優雅的設計便是將所有I/O對象抽象為文件,本質上文件只是一個字節序列,這個字節序列可能存儲在磁盤上,也可能來自網卡,也可能來自鍵盤輸入,也可能來自其他程序輸出,等等等等。這樣做的好處是linux只需要提供少數簡單一致的api接口來實現輸入和輸出,比如read write

主要目錄

  • / 根目錄,存放著系統核心程序
  • /usr unix software resource的縮寫,存放unix廠商(可能是改版的發行者)開發的軟件資源
  • /usr/local 存放用戶安裝的軟件資源
  • /opt option(選裝),存放第三方廠商開發的軟件資源
  • /lost+found 標準ext2/ext3文件系統才會有該目錄,主要是在文件系統異常時暫存碎片,日后恢復
  • /boot 系統啟動所需程序
  • /home 系統用戶主文件夾
  • /mnt 臨時設備掛載點
  • /log 非日志目錄,而是與用戶登錄相關
  • /var 主要存放一些經常變化的文件,和系統運行過程中產生的文件
    • /var/run 一般是各個進程用于存放運行時的信息,如nginx.id
    • /var/lock 進程控制資源的鎖
    • /var/cache 進程運行中的一些緩存
  • /proc 這個目錄比較特殊,是一個虛擬文件系統,保存著系統內核,進程,外設,網絡等的狀態,數據全在內存中,本身不占用任何硬盤空間,比較重要的目錄有/proc/cpuinfo, /proc/ioports, /proc/net/*

此外還有一些目錄經常成套出現在以上個別目錄中,意義是差不多的

  • /bin 二進制可執行文件,在 / 中為與系統運行相關
  • /sbin 二進制可執行文件,主要是系統維護相關
  • /include c/c++常用頭文件,我們在以源碼包方式編譯安裝軟件時,會使用
  • /lib 應用軟件的函數庫,目標文件
  • /etc 配置文件
  • /src 源碼
  • /tmp 臨時文件夾

注意linux中文件的目錄結構只是邏輯結構, 真正的物理結構還要看實際掛載位置。比如/home掛載在硬盤1,/home/liufuxin可能掛載在硬盤2

inode

inode可以理解為文件的元信息,linux中每個文件都會對應一個inode,inode中包含文件的權限、字節、存儲位置、鏈接數、最近訪問信息等,理解inode有助于理解文件的權限和鏈接

  • 普通文件,包含一個文件名和inode號,讀取文件其實是三步:讀取文件的inode號、獲取inode信息、讀取數據
  • 目錄文件,內容為目錄包含的文件和文件的inode號,有目錄的r權限,則可以看文件名,但如果沒有x權限,則因為無法解析inode則不能獲取大小、權限、最近訪問等信息,更不能讀取文件內容和寫文件

相關命令

  • ls -i 查看文件inode號
  • stat file 查看文件inode信息

文件權限

linux中每個文件(目錄本質也是文件),都會有一組以下權限串rwxrwxrwx

  • r 代表讀權限
  • w 代表寫權限
  • x 代表執行權限

而三組rwx則依次代表了文件創建者,文件用戶組,其他人的權限。通常也會用三個八進制數來表示權限,比如rwxrwxrwx會用777表示,r-x-wx---530表示

注意rwx對于文件和目錄的意義有著一些差別

對于file

  • r 是否可以讀取文件內容
  • w 是否可以更改文件內容
  • x 是否可以執行文件

對于dir

  • r 是否可以讀取到目錄中文件
  • w 是否可以在目錄中新建,刪除,重命名
  • x
    • 是否可以cd進入目錄;
    • 是否可以解析包含文件的inode信息,這就導致x其實是rw的前提(即便有r權限,可以知道文件名但因為無法讀取inode,不能獲取文件類型大小等);
    • x權限是會影響子目錄的,rw不會,即無父目錄的rw,也不影響子的rw權限;

權限修改
文件權限修改有兩種辦法

  • chmod 777 file
  • chmod [a|u|g|o]+r-w file u為擁有者,g為用戶組,o為其他,a為全部,+為添加,-為去掉,比遷一種要容易記一些

相關命令

  • chgrp 修改文件用戶組, chgrp [-R] users file, 改變file文件的用戶組為users,-R為遞歸修改
  • chown 修改文件擁有者, chown [-R] user[:group] file, 除了改變文件擁有者,還可以修改文件用戶組

默認權限
umask控制,類似子網掩碼. 創建文件時,系統會去掉umask標記的權限,比如umask為111則創建的文件權限為666
但要注意,無論umask如何設置新建的文件都不會具有x權限,這也是經常出錯的地方,為了安全起見, 一般umask為022

  • umask 查看umask值
  • umask 022 設置umask

SetUID (SUID)
想想這樣的場景, /etc/shadow文件中保存著所有用戶的密碼信息,只有管理員能查看。/usr/bin/passwd為修改密碼程序,所有用戶都有執行該程序的權限, 但是我們進程的權限與啟動用戶一致的, 那非管理員啟動的passwd進程是如何修改密碼呢?

特殊權限SetUID就是處理該場景, 當文件擁有者的權限中執行位為s時, 其他用戶執行該文件期間可以具有擁有者的權限,僅對二進制文件有效,所以只需要為passwd二進制文件添加該權限即可讓普通用戶執行該程序時擁有管理員權限,同時只能按照程序提供的操作執行。類似的還有SetGID(SGID), 表明執行期間擁有文件所在用戶組的權限

Sticky Bit (SBIT)
想想這樣的場景, 團隊公共目錄 ~/work, 所有人都擁有該目錄的x權限, 若再具有w權限則能夠進行刪減和重命名, 如何避免誤操作?
只需要為目錄設置SBIT權限即可, SBIT只對目錄有效, 設置后僅有root或擁有者可以刪減對應文件

SUID SGID SBIT權限修改。第一種是在原來三位權限前再添加一位

  • 4 SUID
  • 2 SGID
  • 1 SBIT

比如chmod 4666 file,或者使用符號, chmod u+s|g+s|o+t file,注意當看到S或者T時, 說明無效, 比如不具備目錄w權限, t就無效

軟/硬鏈接

linux中有軟硬鏈接文件, 可以方便用戶管理和使用文件系統

硬鏈接
并未創建新的inode節點, 只是新建了一個文件, 并指向源inode, 通過ls -i可以看到文件的鏈接數+1。當刪除源文件時, 不會影響鏈接文件,刪除硬鏈接文件則會導致源文件inode鏈接數-1,為0時inode也會被刪除。創建硬鏈接ln source target

因為是公用inode所以就決定, 硬鏈接不能跨文件系統, 不能遠程。而且由于硬連接指向了inode,所以當源文件被刪除時,真正的inode不會被刪除,硬連接依舊正常使用。軟連接則不行;同時目前硬鏈接不支持目標文件為目錄

軟鏈接
新建了一個鏈接文件, 然后這個文件的內容是鏈接文件的路徑,注意這是兩個文件、兩個inode, 類似windows的快捷方式, 創建方式ln -s source target。刪除軟鏈接文件不會影響源文件,刪除源文件則會導致軟鏈接無法正常使用

編碼

計算機中的所有數據本質上都是01序列,只特定的上下文中,賦予了01序列實際意義

數據表示

  • 一個0、1為1個bit,即一位
  • 8個bit為一個byte,即一個字節
  • 2個byte為一個word,即一個字
  • 一般使用4個byte表示int,1個byte表示char

ASCII UTF-8 Unicode

  • unicode是對全世界所有字符的一種編碼,用4個byte來標記一個字符,稱為統一字符集
  • ascii則是計算機早期的一種字符編碼,用1個byte來表示一個字符,主要用來表示英文字母、常用符號
  • utf-8,unicode trans format,unicode傳輸格式,是一種為了節約空間對Unicode字符集的一種編碼方式,將常用的字符如英文字符使用1個byte表示,用3個byte來表示中文字符
  • gb2312是漢字最早的編碼格式,gbk是其擴展,收錄了更多漢字(不含繁體)和少數民族文字

大端、小端
比如整數255的字節表示為01 00,01被稱為最高有效字節,00稱為最低有效字節,所以

  • 大端模式是指計算機在存儲數據時,最高有效字節在前,最低在后,即 01 00
  • 小端模式是指計算機在存儲數據時,最低有效字節在前,即00 01

需要注意的是為了數據在網絡中交換,規定網絡數據一律使用大端模式

延伸
網頁編碼那點事

重定向

系統會為每個程序都默認打開3個標準文件標示符,0標準輸1,1標準輸出,2標準錯誤輸出,程序可以通過與文件標識符交互(read、write)完成讀取輸入和輸出結果

重定向程序輸出時,> 覆蓋式寫,>> 追加式寫,&的作用是獲取其后文件標示符表示的設備

/bin/sh script 1> out 2> err,注意>前無空格,否則1、2就變成‘參數’了

/bin/sh script 1>out 2>&1,標準輸出到out,然后標準錯誤輸出重定向到標準輸出,注意順序和無空格

/bin/sh script &> out,將標準輸出和錯誤都輸出到out

注意/bin/sh script 1>list 2>list是錯誤寫法,這樣寫會導致兩個輸出混在一起

虛擬內存

一臺計算機的存儲設備一般包括寄存器、主存(內存)、硬盤,現在考慮這些問題:

  1. cpu只能直接與寄存器進行交互,而且只能直接讀寫內存中的數據,那么如何高效的將數據從硬盤中載入寄存器供cpu使用?
  2. 系統中有成百上千的進程在同時運行,每個進程的執行命令、處理數據、輸出結果都依賴內存,如何管理內存?

虛擬內存便是操作系統用來維護計算機存儲設備的機制。其基本模型是將內存、硬盤都劃分為以頁為基本元素的大的數組。

基于這個模型,使用“文件”這個概念來維護硬盤中的數據,文件記錄了其所代表的數據在磁盤的所有頁的位置

進程申請內存便是為其在內存中分配頁槽位,釋放內存便是釋放這些槽位,read文件數據便是將文件的頁從磁盤讀入到內存的頁槽中。操作系統維護著內存中每個頁槽屬于哪個進程,來保證進程內存之間的隔離,同時給每個進程造成一種在“獨占”內存的假象(在進程看來,自己的內存空間是連續的)

就是這么一個簡單的模型,保證了數據有序的在硬盤、內存、寄存器之間有序維護

緩存
寄存器的讀取速度為1個單位的話,那么內存的讀取速度就是10個單位,而硬盤的讀取速度則是100000個單位,如果每次從文件讀取數據都要由硬盤重新讀取的話,那么cpu資源將極大浪費

操作系統使用緩存來解決不同存儲設備讀取速度巨大差距的問題。當進程申請將一頁從硬盤讀入進程的頁槽中時,操作系統會先把頁加載到內核進程的頁槽中,再copy到進程的頁槽中,之后的一定時間內當其他進程再申請同一個頁時,便可以直接在內存中copy

而且由于當前硬盤的構造,讀取時間基本消耗在尋址階段,當找到頁后,順序讀取時,其實只需要大約10個單位的時間,所以操作系統在加載頁時,也會順便把該頁前后的頁也順帶加載,根據程序的局部性原理這些頁大概率會在接下來的時間內被申請

程序的局部性原理,是指時間的維度看同一份數據大概率會在短時間內被程序反復使用,或者從空間的維度看一份數據一旦被程序使用,那么它相鄰的數據也大概率會被程序使用

正是局部性原理,保證了可以進行緩存。試想如果一個程序天上一腳、地下一腳的讀取數據,那么操作系統就只能反復從硬盤中加載數據,這也是一些程序性能差的原因之一

延遲寫
另一項操作系統提供性能的策略是延遲寫,當進程修改頁中的數據時,操作系統不會立刻刷會硬盤中,因為進程可能會短時間內頻繁操作,而且刷回硬盤需要大量時間。被修改的頁(稱為臟頁)會在內核空間中停留一段時間后,根據不同的策略再刷回硬盤

進程

進程簡單來說,就是操作系統一個可執行程序的實例,是對計算機計算能力(cpu)+ 存儲能力(主存)+ 交互能力(I/O設備)的抽象

通過進程,你可以對三者完全無感知的情況下來控制計算機。比如我們寫程序從文件讀入一個字符串,并不需要知道文件數據如何存儲在硬盤,處理整個字符串也并不需要知道執行哪些cpu指令,把他打印出來也不需要知道外設如何使用

類似地,文件是操作系統對I/O設備的抽象。虛擬內存是對I/O設備+主存的抽象

我們來利用計算機工作,就必須執行具體的程序,生成進程來完成

進程基本知識點

  • 進程必有pid,與線程的共用一個計數,所以有可能不連續
  • 進程必有ppid,父進程,1號進程除外
  • 進程必有名稱
  • 進程必有退出碼,0~255

進程的內存結構

進程會給程序一種假象,他是在獨占地使用計算機的計算、存儲資源。這樣不僅可以最大程度發揮計算機硬件性能,而且降低程序的開發難度,進程互相之間不需要操心彼此影響(高級編程除外)。而要實現這一點,進程的內存就必須互相隔離,操作系統利用虛擬內存機制來實現這一點。下面是進程的典型內存結構

image

依舊把進程的內存空間想象為一個很長的頁槽數組

  • 所有進程的0x004000000位開始是進程的指令序列,即text段,是在進程啟動前完成加載的(這就是為什么更改已經運行的程序源碼不會影響進程)
  • text段之上是static段包含由編譯器所分配的變量,包括全局變量,和使用static聲明的局部變量;
  • 再往上是heap段進程運行過程中間的內存擴展部分;
  • 再之上是共享庫的內存空間;
  • 最頂部對用戶進程隱藏的是內核的虛擬內存;往下是進程運行過程中的棧空間stack段(用來執行函數、線程等);

所以,一個程序(也就是進程)運行時,是先把運行代碼加載到text段,編譯期間的靜態變量、全局變量等都加載在static段。運行過程中需要讀取的文件內容等存放在heap段,申請內存也加塞在這。需要執行公共庫的代碼、數據則在公共空間;系統調用所需的代碼、數據則在最頂部。本地的函數創建調用則在用戶棧里完成,調用時入棧、完成時出棧。

而且得益于虛擬內存,那些公共的部分看似進程獨有,其實是進程間共享的,并沒有浪費內存空間,還保證了進程內存空間的簡單性

用戶模式 & 內核模式

進程運行模式機制主要是為了防止惡意進程非法訪問其他進程的數據,或者進行破壞,進程在正常運行是在用戶模式下,當需要進行一些‘高難度’操作比如讀取文件、使用顯示器顯示數據等,則需要通過操作系統提供的系統調用來進行,此時進程的運行模式為內核模式,進程執行的指令跳轉到內存的頂層內核指令空間,等待系統再次指定進入進程自己的指令空間

程序編譯

進程是可執行程序的實例,那么可執行程序又是如何來的?

以c語言為例。我們在寫好程序之后,編譯器(如gcc)會把這些程序文本編譯為匯編代碼,然后再通過匯編器生成目標文件(不同的機器因為cpu指令集合可能不同,需要不同的匯編器),最終目標文件鏈接起來就是0、1組成的可執行文件了

鏈接
為什么不直接匯編生成可執行代碼,還要經過一次鏈接?

最初的程序確實是這樣,經過匯編之后產生的就是可執行文件,但實踐證明這種模式并不高效,比如打印字符到顯示器這樣的功能代碼段,大部分程序都需要,我們就必須在所有程序里重復實現,很傻是不是?所以就有了鏈接,把這些常用的程序提前匯編為目標代碼,執行前鏈接一下就好。這樣的的另一個好處就是減少編譯時間,比如我就修改了一個目標文件的源碼,只需要重新編譯該目標文件即可,難道我要把整個項目都編譯一遍嗎?

動態庫 & 靜態庫
跟鏈接的情況類似,還是打印字符到顯示器這樣的指令集合,難道要在每個進程的內存空間都加載一模一樣的代碼嗎?

進程內存空間中共享內存便是這個作用,將常用的庫在進程之間共享,這就是靜態庫。而動態庫是指有些指令集合也是標準的,但使用頻率很低,而且可以在操作系統執行期間動態加入,既不能也沒必要提前加載,進程會在實際需要運行的時候,動態將指令空間加載進內存空間

為了避免從硬盤中加載代碼進主存,操作系統會提前把動態庫的代碼加載進主存,所以當更新了動態庫后,需要執行ldconfig來重新加載。lld可以查看一個可執行程序所依賴的動態庫

進程狀態

當進程被創建時,操作系統會為進程分配包含進程信息的數據結構,稱為“進程控制塊”(PCB),PCB跟蹤進程的狀態,主要包括:

  • 運行(Running),如果進程正在運行于某個核心上
  • 就緒(Ready),如果進程可以但沒有運行,通常由于就緒進程數量大于內核的數量
  • 阻塞(Blocked),如果進程由于正在等待未來的事件,例如網絡通信或磁盤讀取,而不能運行
  • 終止(Done):如果進程運行完畢,但是帶有沒有讀取的退出狀態信息

文件描述符

進程有一個描述符表用正整數來表示進程已經打開的文件。操作系統會在進程創建時預先為其打開文件,并提前打開3個標準文件,0標準輸出,1標準輸入,2標準錯誤輸出

同時操作系統會全局維護一個文件表記錄所有被進程打開的文件,以及他們被引用的次數,文件被刪除時,只有當引用數為0時才會真正從系統刪除,所以進程要及時關閉不使用的文件

進程的并發

最初的計算機都是單任務的,同一時間只能做一件事,這樣如果一個任務包含長時間的IO等操作,所有任務都得阻塞。為了解決這個問題,操作系統加入了進程概念,可以同時運行多個進程,從而實現多任務

并發 & 并行
并發是指同一個時間段內有多個進程在運行。并行是并發的真子集,意思同一個時間點有多個進程在運行,需要多cpu支持

上下文切換
操作系統實現進程并發的模型很簡單,就是cpu不斷在多個進程之間進行切換運行,由于cpu的周期非常短,所以多個進程看似是在同時運行,不過如果進程數不多于cpu核數的話,進程則確實是在同時運行,不過多數情況是進程數要多于cpu核數,進程需要交替運行

進程讓出cpu的使用權叫做上下文切換,內核不僅需要保存出讓cpu使用權進程的各種信息,同時還要載入將運行的進程信息,這些信息被稱為上下文,包括通用寄存器、浮點寄存器、程序計數器、用戶棧、狀態寄存器、內核棧和各種內核數據結構,比如描述地址空間的頁表、包含當前有關進程信息的進程表,以及包含進程已打開文件的文件表

上下文切換的代價還是挺大的,大約是幾千個周期或幾毫秒,甚至可能是操作系統cpu周期耗費的主要地方,所以多進程并不一定比單進程快,在計算密集的場景下,頻繁的進程切換反而會效率更差

異常
最初的進程切換是進程互相協調的,但很快發現這種模式容易導致惡意進程搶占運行資源,所以目前主流操作系統都使用競爭式進程搶占,由操作系統來負責進程之間的切換,這個機制便是異常

當觸發異常時,比如讀取文件、讀取網絡數據,或者其他硬件觸發的中斷,進程會從運行狀態,轉變為掛起、或者終止(由異常是否可以恢復決定),進程會在等待條件滿足時,再次進入就緒態,等待下一次調度

fork & exec

進程可以fork一個子進程,子進程會復制父進程的內存空間,包括父進程的文件表,即子進程會默認打開父進程已打開的所有文件,這個要特別注意,而且操作系統為了提高性能,實現了寫時復制機制,即只有子進程的內存發生寫入時才會觸發內存復制

exec則是在當前進程的上下文環境中啟動一個新進程來代替當前進程,在該進程執行結束之后再恢復之前的進程

守護進程

守護進程(daemon)就是一直運行的進程

web服務器就是一個守護進程,你登錄服務器打開的對話窗口也是個守護進程,你寫一個死循環的程序執行后也是守護進程(雖然是個垃圾)。所以守護進程最主要的特征是一直運行(直到被主動關閉)。排除掉進程出錯導致退出的原因,導致進程退出的原因有:

  • 進程出錯,異常退出
  • 進程收到非預期的SIGHUP信號,退出

后臺任務

守護進程基本都在后臺執行,這樣不會占用命令行窗口。所以守護化的第一步便是讓進程后臺執行

  • test.sh &,添加&便可以讓進程直接后臺執行
  • 對于已經前臺執行的進程,需要先掛起ctrl + z然后再執行bg(讓最近一個掛起的任務后臺繼續執行,fg恢復)

后臺任務與前臺任務的主要區別是,不再繼承session的標準輸入,所以除非后臺進程標準輸入被重定向,否則無法讀取輸入,而且會導致阻塞。但后臺任務繼承了seesion的標準輸出和標準錯誤,所以進程的輸出信息依舊會打印在會話窗口

守護化進程

  1. 關閉huponexit(默認即為關閉),則session進程退出后便不會向后臺任務發送SIGHUP信號,后臺任務就可以一直運行下去了
  2. 當huponexit為開啟時,便需要disown命名,作用是既可以讓后臺任務忽略SIGHUP信號,也可以直接從會話組中踢出后臺任務(交給1號進程),常使用的命令為
    • disown,移出最近一個正在執行的后臺任務
    • disown -r,移出所有正在執行的后臺任務
    • disown -a,移出所有后臺任務
    • disown -h,不移出后臺任務,但是讓它們不會收到SIGHUP信號
    • disown -h %2,根據jobId,移出指定的后臺任務
      需要注意的事,進程繼承了session的標準I/O,一旦發生讀寫,會因為session已經退出而報錯。所以需要事前重定向要守護化的進程的標準I/O
  3. 比disown更方便的是直接使用nohup,作用為
    • 該進程忽略SIGHUP信號
    • 關閉標準輸入,該進程不再能夠接受任何輸入
    • 重定向標準輸出和標準錯誤到文件nohup.out
      需要注意的是nohup并不會把進程變為后臺任務,需要主動加上&

以上是將一個普通進程守護化,如果想在程序中直接實現以上功能,思路也一樣,但需要使用編程語言來操作諸如后臺執行(利用fork)、脫離進程組、重定向IO、忽略SIGHUP信號、改變工作目錄、清理掩碼。更為可靠則是父進程只負責在子進程退出后重新拉起,具體的程序邏輯則在子進程中執行

僵尸進程、孤兒進程

孤兒進程指父進程退出,仍在運行的進程,這些進程被移交給1號進程,比如前面的disown操作。孤兒進程基本沒什么危害,等待其正常結束或者直接kill即可

僵尸進程則是該進程已經結束,但父進程未執行wait操作,導致內核依舊保留其退出信息,如果大量產生的話會導致內核資源耗盡,危害很大。解決辦法是kill掉父進程,子進程便都移交1號進程回收

延伸
Linux 守護進程的啟動方法

進程間通信

線程

線程是cpu調度的基本單位,其實每個進程至少要包含一個線程

同一個進程中的線程互相之間共享進程的內存空間

線程的切換成本主要是寄存器、計數器等,要遠低于進程切換成本

線程安全

線程安全是指一個函數在多個線程同時調用的場景下,輸出結果保持一致,反之則為線程不安全

線程不安全的函數可能是依賴了靜態變量、全局變量,或者線程之間共享的進程變量沒有加鎖維護一致性

協程

簡單小結一下

  • 協程并非操作系統概念,內核無此概念
  • 協程為用戶級線程,線程自己負責協程的調度
  • 適合I/O密集型場景
  • windows下叫纖程

網絡編程

由于一切皆文件的抽象,網絡編程其實就是利用網卡這個特殊的文件進行編程,這個‘文件’字節流的交換是由多種網絡協議與以太網來實現的

port端口

端口是操作系統對外提供服務的進程的抽象,每個提供服務的端口背后都對應一個進程

端口由一個整數表示,從0到65535,其中0-1023為著名端口,這些端口會由一些基礎服務占用;1024-49151為注冊端口,這些端口是建議給用戶進程服務使用的;49152-65535則是動態端口一般是臨時分配的

socket套接字

網卡是用來進行網絡數據交換的設備,維護著本地進程與外界大量的網絡連接,socket套接字則是這些連接的抽象。socket由四個字段確定:本機ip、服務端口、連接ip、連接的端口,socket本質也是一個文件,記錄了其緩沖區,排隊進程隊列

當本地進程是提供服務的進程時,端口號是固定的由進程申請bind。當本地進程是發起外界建立連接時,本地的端口是隨機分配的

在實際編程中socket在不同語境下意思有所不同,系統調用socket返回的是“監聽socket描述字”,他只有服務端ip+port;而accept函數返回的是“已連接的socket描述字”,包含服務端ip+port和客戶端ip+port,定義了一個tcp連接

I/O多路復用

很多資料講到這部分都是直接開懟socket、同步異步、阻塞非阻塞、select、poll,顯得高深莫測。其實多路復用要解決的是這種場景:監聽多個I/O設備,比如你需要監聽多個文件的修改、實現一個網絡服務器、監聽多個socket文件,我們一步步開始

  1. 創建一個socket監聽,bind了9000,輪詢accept,建立連接、讀取并處理數據。優點是簡單,缺點是不斷輪詢也造成了cpu資源浪費
  2. 多路復用要登場了,把多個socket傳給select系統調用,設置阻塞,這樣當有socket活躍(新連接建立或已有連接數據進入)時select才會返回,此時再輪詢即可。優點是不再需要定期輪詢,缺點是
    1. select最大支持1024個socket
    2. 每次select被喚醒,都需要進行遍歷才能獲取活躍socket
    3. 因為select是系統調用,所以每次都要把所有socket參數復制進內核空間
    4. select的底層實現性能并不高,需要反復將進程加入/刪除socket的就緒隊列
  3. 用poll替換select,最大連接數不再受限
  4. 使用epoll。簡單說就是把要監聽的socket都丟到事件池中,然后注冊事件觸發時的回調函數,這樣每當有socket活躍時,就會自動執行回調函數,非常高效,優點包括
    1. 連接數沒有限制,理論上只受進程打開文件最大數限制
    2. 事件池可以避免socket的反復移除進入
    3. epoll維護了就緒列表,記錄了就緒的socket,無需遍歷
    4. epoll的底層實現避免了反復操作socket等待隊列
      其實epoll的出現大大降低了連接的維持成本,使得單臺服務器可以很容易就解決C10K問題

至此,我們一步步的解決了大量連接I/O的復用問題,服務器可以保持大量的連接。但是,仍然有一個致命問題連接的處理是一個進程,處理期間,其他連接只能等待,效率非常差。我們需要繼續解決連接的處理性能問題

服務器模型

  1. 最簡單的,來一個請求我就fork一個子進程進行處理。優點是簡單,缺點是頻繁的進程創建和銷毀非常消耗系統資源。其實這就是最初的fork-execute模型
  2. 要避免進程頻繁創建銷毀,我們可設計一個master進程維護一個worker進程池,處理完任務后不退出。這就是leader-follower模型
  3. 服務器其實要解決的就兩個問題,大量連接的維護問題和活躍連接的處理問題。使用epoll可以解決大量連接的維護問題,使用leader-follower可以解決請求處理問題,合起來就是reactor模型

真實研發中根據實際情況的不同,會使用線程、協程替代進程。可能有多個reactor或者多個master。編程語言可以自己維護服務器連接模型、請求處理模型,也可以由通用服務器如apache nginx維護

同步、異步 & 阻塞、非阻塞
在上面的總結中可以繞過了同步異步、阻塞非阻塞的概念。因為這幾個概念就我查的資料來看,比較混亂。究其原因,我認為主要是大家預設的場景不同

同步、異步,比如前面說的網絡模型,select我們認為是同步的,因為發起IO后,必須等待或者輪詢,就緒后才能繼續處理;epoll我們認為是異步的,因為我們提前注冊了回調方法,發起IO就緒后系統會自動調用回調方法。但如果放在IO的場景,無論select還是epoll都是同步的,因為他們的區別只是識別活躍socket的性能不同,處理活躍socket仍然是需要同步阻塞進行recv的。除非使用AIO


同步阻塞.jpg

阻塞、非阻塞,則比較好理解,就是發起調用后進程的狀態,是否進入Blocked狀態

綜上,其實一直要解決的問題是如何降低活躍連接的發現成本(利用epoll減少數據移動、減少文件遍歷),和如何降低請求處理的調度成本(復用進程減少創建成本、使用線程協程降低上下文切換成本),盡可能將機器資源用于請求處理,提高并發

延伸
如果這篇文章說不清 epoll 的本質,那就過來掐死我吧
高性能IO模型淺析
Linux IO模式及 select、poll、epoll詳解

Vim

使用linux中必不可免的要進行文本操作,你有很多選擇,但建議使用vim,因為linux默認安裝,同時功能強大,這里總結一些常用操作

行內移動

  • 0 移動到行首
  • ^ 移動到行首第一個非空字符
  • $ 移動到行尾
  • g_ 移動到行尾最后一個非空字符
  • w 移動到下一單詞開頭,e 移動到下一單詞結尾,默認上來說,一個單詞由字母,數字和下劃線組成(陳皓注:程序變量)
  • 如果你認為單詞是由blank字符分隔符,那么你需要使用大寫的E和W。(陳皓注:程序語句)
  • % 括號匹配移動
  • *、# 當前單詞匹配移動,下一個/上一個

復制粘貼

  • v 視圖模式
  • V 視圖行模式
  • y 復制選中部分
  • yy 復制當前行
  • p 粘貼至下一行
  • P 粘貼至上一行

文件操作

  • :e /file/path 打開文件
  • :bn :bp 打開下/上一文件
  • :saveas /file/save/as/path 另存為

編輯

  • dd 刪除當前行,并把刪除的行存到剪貼板里
  • 10ia [ESC] 會插入10個a
  • . 重復最近一次編輯
  • 3. 重復3次最近一次編輯
  • ctrl+a 自增

塊操作

  • c-v 選擇塊區域,c-d向下移動,或者hjkl,或者%
  • I 批量插入,按[ESC]生效
  • J 將所選的行變為一行
  • > < 縮進
  • = 自動縮進
  • gu gU 改變大小寫

提示
插入模式下,c-n c-p 自動提示

分屏

  • :split :vsplit 水平、垂直分屏
  • c-w dir 方向,屏間切換
  • c-w+/- 放大縮小屏
  • c-w > < 改變寬度
  • c-w|/_ 最大化垂直屏活水平屏

范圍操作模式
操作 + 范圍

y3j    # 復制之后3行
d3j    # 刪除之后3行
gU3j    # 之后3行轉大寫

常用配置

set enc=utf-8
set nowrap
set ts=4
set mouse=a
set nu
set relativenumber
set nobackup
syntax enable
:suspend 掛起
set paste 粘貼的時候不會錯位
set nobomb|bomb|bomb? 刪除bomb、添加、查看

范圍操作

  • cw 刪除當前所在位置到word結束,并進入insert
  • caw 刪除當前所在位置的word頭到尾,并insert
  • ci" 刪除" 里面的東西
  • ca" 刪除"里的東西,包括"
  • yi"
  • ya" ya(

常用工具與腳本

cat

# 不要忘了cat是可以同時顯示多個文件的
cat file1 file2 ...

# 壓縮空白行
cat -s file1

# 顯示行號,針對所有行,-b則只針對非空白行
cat -n file1

find

# 未指明搜索條件,則列出dir目錄及其子目錄的所有文件
find dir

# 文件名稱搜索,*為通配符,匹配任意多的字符,例子即為以Target開頭的文件 -iname為忽略大小寫
find dir -name "Target*"

# 文件類型搜索,f為文件,d為目錄,l為符號鏈接,s為套接字,p為管道,b為塊文件
find dir -type [fdlspb]

# 多個搜索條件,-o為'或' -a為'與'
find dir -name traget -[oa] -type d

# 指定搜索的最大|小深度,據不可靠消息,深度應該放在搜索條件的第一個,否則系統將搜索出來全部后再過濾層次
find dir -[maxdepth|mindepth] 2 -name 'Target'

# 使用正則表達式搜索,注意匹配的是find的輸出結果,而不是如-name那樣只匹配文件名
find dir -regex ".*\.jpg"

# 文件大小搜索,'+'為'大于','-'為'小于',不寫為等于;
# 'b'    for 512-byte blocks (this is the default if no suffix is used)
# 'c'    for bytes
# 'w'    for two-byte words
# 'k'    for Kilobytes (units of 1024 bytes)
# 'M'    for Megabytes (units of 1048576 bytes)
# 'G'    for Gigabytes (units of 1073741824 bytes)
find dir -size [±]2[bcwkMG]

# 按照時間搜索,首先明白Linux文件系統每個文件都有三個時間戳
# 搜索的單位是天,-n指n天以內,+n指n天以前,無是等于,另外amin|mmin|cmin類似,但單位是分鐘
# 訪問時間(-atime): 用戶最后一次訪問文件時間
# 修改時間(-mtime): 文件內容最后一次修改時間
# 變化時間(-ctime): 文件元數據(權限或所有權,即inode)最后一次修改時間
find dir -atime|-mtime|-ctime [±]2

# 按照文件所有者搜索
find dir -user UNAME

# 按照文件權限搜索
find dir -perm 665

xargs

# 將標準輸入轉化為命令行參數,比如現在有這樣的一個樣本
cat args
1
2 2 2
3 3
4

# -I指定占位符
cat args | xargs -n 1 | xargs -I{} mv {} dir

sort

# sort是非穩定的,即除了排序的key外,每次排序的執行結果順序可能不同
# 依次排序各個文件
sort file1 file2 ...

# 按照數字序對文件內容進行排序
sort -n file1

# 逆序
sort -r file2

# 假如file2中數據存在多列,-k指定使用第二列進行排序
sort -k 2 file1

# 以第二列中的第一個字符到末尾進行排序
sort -k 2.1 file1

# 以第二列中的第一個字符到第二個字符進行排序
sort -k 2.1,2.2 file1

uniq

# 將標準輸入中的連續多行只輸出一行,“連續多行”就決定了uniq處理的標準輸入一般是排過序的,否則無意義
sort unsorted | uniq

# 只顯示唯一的行
sort unsorted | uniq -u

# 同時輸出行的重復次數
sort unsorted | uniq -c

split

# 以大小切分文件生成諸如`xaa xab xac ...`
split -b 10[c|k|m|g] Bigfile

# 同上,但是以行數切分
split -l 100 Bigfile

# -d選項表示使用數字作為生成文件的名字,如`x001 x002 x003 ...`
split -d -l 100 Bigfile

# 最后一個參數定義切分文件的前綴,如`mypre-001 mypre-002 ...`
split -d -l 100 Bigfile mypre-

# 合并切分文件的方法
cat mypre* > merge

dd

# if為輸入文件,/dev/zero為linux特殊設備,會不斷產生\0
# of為輸出文件
# bs為塊大小
# count為塊數,即文件最終大小為 bs*count
dd if=/dev/zero of=junk.data bs=1[c|k|m|g] count=1

mkdir

# 用以創建長路徑
mkdir -p /this/is/a/long/long/path

ln

# 為~目錄創建一個名為home的軟鏈接,可以通過`ls -l`查看,也可以使用`readlink`查看
ln -s ~ ./home

# 硬鏈接
ln ~ ./home

head & tail

# 顯示前5行
head -n 5 file

# 顯示后5行
tail -n 5 file

# 動態跟蹤file變化,此外`-F`選項甚至可以在文件被重命名后依然跟蹤
tail -f file

ls

# 列出詳細信息
ls -l

# 隱藏文件
ls -a

# 顯示目錄本身的信息,而不是目錄里的內容
ls -d Dir

wc

# 計算file的字節數、單詞數、行數
wc -c|w|l file

chmod

# 直接修改
chmod 751 file

# 直接修改,但更加便于理解,a=all u=user g=group o=other w=write r=read x=execute
chmod u=wr,go=x file

# 在原基礎上對權限進行修改
chmod u+w,g-r file

chown chgrp

# 修改文件的用戶組為teachers
chgrp teachers file

# 修改文件的所有者為me,同時用戶組修改為teachers
chown me:teachers file

grep

# 基本用法
grep 'php' file
grep "^a-z" file

# 使用拓展正則模式,此時無需轉義
grep -E "^[0-9]{1,3}" file

# 一般用法,高亮顯示
STDIN | grep MATCHPATTERN --color=auto

# 反向匹配
STDIN | grep -v MATCHPATTERN --color=auto

# 忽略大小寫
STDIN | grep -i MATCHPATTERN

# 靜默,常用于驗證
STDIN | grep -q MATCHPATTERN

# 找出'test'在哪個文件中,`-L`則恰好相反
grep -l 'test' file1 file2 file3...

# 輸出匹配行的上下文,A為After,B為Before,C為前后各
STDIN | grep test -A|B|C 3

# 以文件的每一行為模式進行匹配
grep -f patternfile file

cut

# 顯示file的第一列,關于列的指定
cut -f 1 file

# 1,3,4 顯示1、3、4列
# 1-4 顯示1到4列
# 2- 顯示第2列,直到最后

# -d選項指定分隔符
cut -f 1 -d ',' file

# -s選項用以去掉不含分隔符的列,比如文件中的注釋、說明性文字
cut -f 1 -s file

# 顯示file的前10個字符,類似的還有-b,顯示的字節
cut -c 10 file

wget

# 最基本的用法,從網絡中下載文件
wget url1 url2 url3

# -O選項指定輸出結果的保存文件,-o選項指定wget執行過程中日志存儲文件
wget url1 -O savefile -o logfile

# --limit-rate 限制下載速度,--quota(-Q)控制下載文件的大小
wget --limit-rate 20[k|m|g] url1 --quota 100m

# 需要http或ftp認證
wget --user username --password pass URL

curl

# curl是比wget更高級的http工具

# curl的基本用法,下載url,--slient表示靜默,--progress顯示進度條
curl [--slient|--progress] URL

# curl默認將下載的內容輸出標準輸出,-O則控制curl輸出到文件,文件名則自動識別,比如 DOMAIN/index.html則下載至index.html;-o選項則指定文件名,此處也可以看出linux各個命令直接選項的混亂
curl URL [-O|-o newfile]

# 指定(多個)header
curl -H "Host: www.baidu.com" -H "Accept-language: en"

# 只顯示響應報文中的頭文件
curl -l|head URL

# 設置http中refer
curl --refer http://www.baidu.com URL

# 設置cookie,當使用cookie文件時`curl URL --cookie-jar cookiefile`
curl URL --cookie "user=liufuxin; pass=hack"

# 指定用戶代理
curl URL --user-agent "Mozilla/5.0"

# 安全驗證
curl -u user:pass URL

tar

# 打包文件,-f參數必須為參數組的最后一項,其后必須緊跟打包文件名
tar -cf demo.tar file1 dir1 dir2

# 提取打包文件,也可以指定提取的文件
tar -xvf demo.tar [file1|dir1|dir2]

# 排除通配符文件
tar --exclude '*.svn' -cvf demo.tar *

# 打包的同時壓縮
tar -cv[j|z]f demo.[gz|bz2].tar *

gzip、bzip

# 只能對一個文件進行壓縮,所以經常和打包命令配合,兩者使用方法類似,bzip效率更好一些,解壓縮命令為gunzip bunzip
# 生成text.gz同時保留原文件
gzip -c test > test.gz

# 列出壓縮信息,包括壓縮前后文件大小、壓縮比率
gzip -l test.gz

# 壓縮比,1最快(--fast) 9最好(--best)
gzip -[1-9|--fast|--best] test

# 列出壓縮文件
gzcat test.gz

base64

# 編碼test,輸出到標準輸出
base64 test

# 解碼
base64 -d test

ping

# ping 10次
ping www.baidu.com -c 10

scp

# 遠程遞歸復制文件夾至本地,反過來即復制到遠程
scp -r user@host:/home/path/dir ./

lsof

# list open files,列出被打開的文件,因為Linux中‘一切皆文件’,所以該命令也可以查看打開的網絡連接和端口
# 查看file文件被哪些進程占用
lsof file

# -r選項為一直執行losf
lsof -r file

# 顯示abc進程打開的文件
lsof -c abc

# 顯示PID 123打開的文件
lsof -p 123

# 顯示文件描述符(fd)為4的文件被哪些進程打開
lsof -d 4

# 查看用戶username的進程打開的文件
lsof -u username

# 46        IPv4 or IPv6
# protocol  TCP or UDP
# hostname  Internet host name
# hostaddr  IPv4地址
# service   /etc/service中的 service name (可以不止一個)
# port      端口號 (可以不止一個)
lsof -i[4|6] [protocol][@hostname|hostaddr][:service|port]

lsof -i tcp@ohaha.ks.edu.cn:ftp
lsof -i :3306

netstat

# 用于顯示各種網絡相關信息
# 列出所有端口
netstat -a

# 列出所有tcp端口,-u為udp
netstat -at

# 只顯示監聽端口
netstat -l

# 在輸出中顯示PID和進程名
netstat -p

# 不顯示主機、端口和用戶名,而用數字代替,可以加速輸出
netstat -n

# 每隔一秒輸出一次
netstat -c

du

# disk used,磁盤使用情況
# 基本用法,列出文件、目錄的大小,單位字節,目錄默認只顯示其子目錄,且顯示一層
du file dir1 file2 dir2

# 遞歸顯示所有
du -a dir

# 以可讀單位顯示,`-b -k -m`字節、kb、mb
du -h dir

# 只顯示目錄的總計,而不是子目錄
du -s dir

df

# 列出磁盤空閑情況
df -h

time

# 列出命令執行時間
# real 開始執行到結束的時間
# user 進程在用戶模式的時間,唯一真正用于執行進程所花費的時間(不包括阻塞、掛起)
# sys  花費在內核模式的時間,唯一真正使用CPU的時間
time COMMOND

watch

# 固定時間間隔監控命令輸出
# 默認2秒執行一次,-n指定為5秒
watch -n 5 COMMOND

# 高亮顯示區別
watch -d COMMOND

ps

# 列出所有進程信息,默認值顯示當前終端進程,`-ax`效果類似
ps -e

# 顯示更多信息
ps -e[f|l]

# 指定要顯示哪些列,常用的有
# pid
# ppid
# pcpu cpu占用率
# pmem 內存使用率
# comm 可執行文件名
# user 啟動用戶
# stat 進程狀態
# time 累計cpu時間
# 排序,-降序,+升序
ps -ef -o [TargetCol]
ps -ef --sort -pcpu,+time

# -L選項列出線程信息
ps -efL

kill

# 列出所有可用信號
kill -l

# 終止一個進程,默認發送的是SIGTERM信號(15),常用
# SIGHUP 1 掛起
# SIGINT 2 中斷,ctrl+c
# SIGKILL 9 強制殺死
# SIGTERM 15 默認的終止進程
# SIGTSTP 20 ctrl+z
kill 13113

# 殺死進程名的所有實例,類似有`pkill`默認使用進程名
killall processname

which、whereis
查詢工具,區別是which是按照PATH變量中的目錄逐個查找
而whereis則是在Linux自己維護的文件數據庫中查找,所以范圍更大。缺點是非實時,數據庫是每天自動更新,你也可以手動更新,updatedb

uptime

# 系統使用時間統計,包括最近1分鐘、5分鐘、15分鐘的系統負載
uptime

uname

# 主機名,`hostname`
uname -n

# 打印內核、硬件架構等詳細信息
uname -a

# 內核版本
uname -r

# 主機類型
uname -m

crontab

# 指定用戶,root使用
crontab -u liufuxin -e

# */5 1,2 5-9 7 * COMMOND
# 每5分 每天的1,2點 每5-9日 每7月 執行任務
# 注意,周跟日月不能同時出現,同時出現不是'與'關系,而是'或'關系
# 注意,Commond的輸出未指定的話會發送郵件

tee

# tee會將標準輸入傳送給某個設備的同時將其輸出到標準輸出
ls | tee lsresult | cat

umask

# 權限掩碼,用于計算文件的默認權限
# 查看
umask

# 編輯
umask 022

# 作用
從777中拿走umask指定的位

# 注意
文件默認不允許添加執行權限,即即使設定umask為000,新建的文件權限也是666,執行權限必須chmod添加;文件沒此限制

查看cpu

# 總核數 = 物理CPU個數 X 每顆物理CPU的核數
# 總邏輯CPU數 = 物理CPU個數 X 每顆物理CPU的核數 X 超線程數

# cpu基本信息
cat /proc/cpuinfo

# 查看物理CPU個數
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l

# 查看每個物理CPU中core的個數(即核數)
cat /proc/cpuinfo| grep "cpu cores"| uniq

# 查看邏輯CPU的個數
cat /proc/cpuinfo| grep "processor"| wc -l

top

# 實時監控系統cpu、進程、內存狀態
# top命令之后
P 為cpu使用占比排序
M 為內存使用占比排序
i 使top不顯示任何閑置或者僵死進程

# 進程狀態
S 可打斷阻塞,比如等待IO就緒
D 不可打斷阻塞,比如正在讀取文件
Z 僵尸進程
R 正在運行
T 處在被跟蹤狀態,如gbd調試

# top第三行顯示當前系統的,其中有兩個值很關鍵:
%id:空閑CPU時間百分比,如果這個值過低,表明系統CPU存在瓶頸;
%wa:等待I/O的CPU時間百分比,如果這個值過高,表明IO存在瓶頸;

環境變量
bashrc與profile都用于保存用戶的環境信息,bashrc用于交互式non-loginshell,而profile用于交互式login shell。
/etc/profile,/etc/bashrc 是系統全局環境變量設定~/.profile,~/.bashrc用戶目錄下的私有環境變量設定
當登入系統獲得一個shell進程時,其讀取環境設置腳本分為三步:

  1. 首先讀入的是全局環境變量設置文件/etc/profile,然后根據其內容讀取額外的文檔,如/etc/profile.d和/etc/inputrc
  2. 讀取當前登錄用戶Home目錄下的文件~/.bash_profile,其次讀取~/.bash_login,最后讀取~/.profile,這三個文檔設定基本上是一樣的,讀取有優先關系
  3. 讀取~/.bashrc

/.profile與~/.bashrc的區別:

  1. 這兩者都具有個性化定制功能
  2. ~/.profile可以設定本用戶專有的路徑,環境變量,等,它只能登入的時候執行一次
  3. ~/.bashrc也是某用戶專有設定文檔,可以設定路徑,命令別名,每次shell script的執行都會使用它一次

用戶管理

# 添加用戶,同時添加home目錄
useradd -m liufuxin

# 設置密碼
paswd liufuxin

# 刪除用戶 -r同時刪除home目錄
userdel -r liufuxin

awk

# 基本格式,BEGIN、END必須大寫,可以省略
awk ’BEGIN {awk-commands} /pattern/ {awk-commands} END {awk-commands}‘ targt.file

# 打印所有行
awk '{print $0}' file

# 統計匹配的行數
awk '/a/{++cnt} END {print "Count = ", cnt}' marks.txt
Count =  4

延伸
三十分鐘入門AWK

sed

# 首處替換,替換每一行的第一處匹配的text
sed 's/text/replace_text/' file

# 全局替換
sed 's/text/replace_text/g' file

# 移除空白行
sed '/^$/d' file

#變量轉換,已匹配的字符串通過標記&來引用.
echo this is en example | sed 's/\w+/[&]/g'
$>[this] [is] [en] [example]

# 子串匹配標記,第一個匹配的括號內容使用標記 1 來引用
sed 's/hello\([0-9]\)/\1/'

延伸
Linux 系統性能分析的 60,000 毫秒
記一次PHP并發性能調優實戰

學習資料

寫給大忙人看的操作系統

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容

  • Ubuntu的發音 Ubuntu,源于非洲祖魯人和科薩人的語言,發作 oo-boon-too 的音。了解發音是有意...
    螢火蟲de夢閱讀 99,419評論 9 467
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數據革命閱讀 12,195評論 2 33
  • 轉載自:http://blog.csdn.net/hguisu/article/details/6122513原作...
    miaoiao閱讀 1,528評論 0 7
  • 前兩天入手的書,今天看了快1/3了。作者的觀點是通過整理房間等與自己相關的物質,來達到精神上的升華。 在日常生活中...
    一只小小的蛹閱讀 290評論 0 0
  • 01 在北京,山窮水盡并不需要你經歷什么大的災難,有時候只需交個房租就能讓你體會到一無所有的感覺。 我第一次租房子...
    球小輝閱讀 283評論 0 0