1. 程式人生 > 實用技巧 >《linux 鳥哥私房菜》

《linux 鳥哥私房菜》

前言

一直以來沒有系統學習過 linux ,今天通過《linux 鳥哥私房菜》這本書好好學習下。

使用者和使用者組

使用者

Linux 系統是一個多使用者多工的分時作業系統,任何一個要使用系統資源的使用者,都必須首先向系統管理員申請一個賬號,然後以這個賬號的身份進入系統。
使用者的賬號一方面可以幫助系統管理員對使用系統的使用者進行跟蹤,並控制他們對系統資源的訪問;另一方面也可以幫助使用者組織檔案,併為使用者提供安全性保護。每個使用者賬號都擁有一個唯一的使用者名稱和各自的口令。使用者在登入時鍵入正確的使用者名稱和口令之後,就能夠進入系統和自己的主目錄。

使用者組

每個使用者都有一個使用者組,系統可以對一個使用者組的所有使用者進行集中管理。不同 Linux 系統對使用者組的規定有所不同,如 Linux 下的使用者屬於與它同名的使用者組,這個使用者組在建立使用者時同時建立。
使用者組的管理涉及使用者組的新增、刪除和修改。組的增加、刪除和修改實際上就是對 /etc/group 檔案的更新。

Linux 檔案屬性

輸入命令

ls -al

會輸出當前目錄下的所有檔案的詳細許可權和屬性。如下:

pwnki@LAPTOP-KETPO6R7:~$ ls -al
total 152
drwxr-xr-x 17 pwnki pwnki  4096 Jan  6 11:16 .
drwxr-xr-x  3 root  root   4096 Dec 20 21:46 ..
lrwxrwxrwx  1 pwnki pwnki    23 Dec 29 10:29 .aws -> /mnt/c/Users/86189/.aws
lrwxrwxrwx  1 pwnki pwnki    25 Dec 29 10:29 .azure -> /mnt/c/Users/86189/.azure
-rw-------  1 pwnki pwnki 17000 Jan  6 21:49 .bash_history
-rw-r--r--  1 pwnki pwnki   220 Dec 20 21:46 .bash_logout
-rw-r--r--  1 pwnki pwnki   200 Dec 28 16:21 .bash_profile
-rw-r--r--  1 pwnki pwnki  3889 Dec 28 16:21 .bashrc
drwxr-xr-x  8 pwnki pwnki  4096 Jan  4 20:24 .cache
drwx------  3 pwnki pwnki  4096 Dec 20 21:46 .config
drwxr-xr-x  4 pwnki pwnki  4096 Dec 29 00:37 ctf_xinetd
drwx------  4 pwnki pwnki  4096 Dec 29 10:48 .docker
drwxr-xr-x  3 pwnki pwnki  4096 Jan  6 11:18 free-libc
-rw-------  1 pwnki pwnki     3 Dec 23 11:29 .gdb_history
  1. 第一列代表這個檔案的型別和許可權。第一個字元代表檔案型別,後面九個字元每三個一組,分別代表檔案所有者的許可權、同用戶組的許可權、其他非本使用者組的許可權。
  2. 第二列代表有多少檔名連線到此節點。
  3. 第三列表示這個檔案(或目錄)的“所有者賬號”
  4. 第四列表示這個檔案的所屬使用者組
  5. 第五列為這個檔案的容量大小,預設為 B。
  6. 第六列為這個檔案的建立日期或者是最近的修改日期。
  7. 第七列為檔名。

改變檔案屬性的許可權

改變檔案所屬使用者組命令 chgrp;改變檔案所有者命令 chown;改變檔案許可權命令 chmod;具體用法參考 man 手冊。

Linux 檔案種類

任何裝置在 Linux 下面都是檔案,不僅如此,連資料通訊的介面也有專門的檔案負責。所以 Linux 有非常多的檔案種類,如下:

  1. 檔案種類

    • 普通檔案。就是一般我們在進行訪問型別的檔案,依照檔案內容,大致可分為三類。
      • 純文字檔案。這是 Linux 系統中最多的一種檔案型別,稱為純文字檔案是因為內容為我們可以直接讀到的資料,例如數字、字母等。幾乎只要我們可以用來作為設定的檔案都屬於這種檔案型別。
      • 二進位制檔案。可執行檔案就是這種格式的。
      • 資料格式檔案。有些程式在執行的過程當中會讀取某些特定格式的檔案,那些特定格式的檔案可以被稱為資料檔案。
  2. 目錄

  3. 連線檔案。類似於 Windows 系統下面的快捷方式。

  4. 裝置與裝置檔案。與系統外設及儲存等相關的一些檔案,通常都集中在 /dev 這個目錄。通常又分為兩種:

    • 塊裝置檔案:就是一些儲存資料,以提供系統隨機訪問的介面裝置,例如硬碟、軟盤等。
    • 字元裝置檔案:也即是一些串列埠的介面裝置,例如鍵盤、滑鼠等。
  5. 套接字。用來在網路上的資料連線。

  6. 管道。FIFO 是一種特殊的檔案型別,它主要的目的在解決多個程式同時訪問一個檔案所造成的錯誤問題。

檔案路徑的變數:$PATH

當我們在執行一個命令的時候(比如說 ls),系統會依照 PATH 的設定去每個 PATH 定義的目錄下查詢檔名為 ls 的可執行檔案,如果 PATH 定義的目錄中含有多個檔名為 ls 的可執行檔案,那麼先查詢到的同名命令先被執行。
可以使用命令

echo $PATH

檢視環境變數 PATH。

shell

bash shell

shell 是一個用 C 語言編寫的程式,它是使用者使用 Linux 的橋樑。Shell 即是一種命令語言,又是一種程式設計語言。Shell 是指一種程式,這個應用程式提供了一個介面,使用者通過這個介面訪問作業系統核心的服務。bash shell 是 Linux 預設的 shell,它有以下幾個優點:

  1. 命令記憶能力。只要在命令列中按上下鍵就可以找到前/後一個輸入的命令。
  2. 命令與檔案補全功能(使用 Tab 鍵)。
  3. 命令別名設定功能(alias)。
  4. 作業控制、前臺、後臺控制。
  5. 程式指令碼(shell script)。

變數的顯示與設定

echo 命令列印變數:

echo $變數名 /echo ${變數名}

使用等號給變數賦值:

變數名=變數值

如果該變數需要在其他子程序執行,則需要以 export 來使變數變成環境變數:

export 變數名

unset 命令取消變數:

unset 變數名

env 命令可以檢視環境變數:

env

set 命令可以檢視 bash 內的全部變數:

set

“$” 本身也是一個變數。這個代表的是目前這個 Shell 的執行緒代號,即所謂的 PID 。可以使用命令查詢 PID:

echo $$

“?” 也是特殊的變數。在 bash 裡面這個變數很重要。這個變數是上一個執行的命令所回傳的值。當我們執行某些命令時,這些命令都會回傳一個執行後的程式碼。一般來說,如果成功執行命令,則會回傳一個 0 值。

環境變數和自定義變數

env 可以檢視環境變數,set 可以檢視環境變數和自定義變數。環境變數和自定義變數的區別就在於該變數是否會被子程序所繼續引用。
當你登入 Linux 並取得一個 bash 後,你的 bash 就是一個獨立的程序。接下來你在 bash 下面所執行的任何命令都是由這個 bash 所衍生出來的,那些被執行的命令就被稱為子程序。而子程序只會繼承父程序的環境變數,而不會繼承父程序的自定義變數。

變數鍵盤讀取、陣列與宣告

read 命令可以輸入變數,執行 read 命令後,系統會等待你從鍵盤讀入變數值:

read 變數名

declare 可以宣告變數型別:

declare [-aixr] 變數名

其中 [-aixr] 引數有以下幾種:

  1. -a:將變數定義為陣列型別。
  2. -i:將變數定義為整數數字。
  3. -x:將變數設定成環境變數。
  4. -r:將變數設定為 readonly 型別,該變數不可被更改內容,也不能重設。

命令別名設定

alitas 可以給命令設定別名:

alitas 別名=‘命令’

unalitas 可以取消別名:

unalitas 別名 

終端環境的設定

使用命令 stty 可以檢視終端機輸入按鍵的含義:

pwnki@LAPTOP-KETPO6R7:/mnt/c/Users/86189$ stty -a
speed 38400 baud; rows 30; columns 120; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q;
stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

常見的有以下幾種:

  1. eof:End of life 的意思,代表結束輸入;
  2. erase: 向後刪除一個字元;
  3. intr: 送出一個 interrupt 的訊號給目前正在執行的程式;
  4. kill:刪除在目前命令列上的所有文字;
  5. quit:送出一個 quit 的訊號給正在執行的程序;
  6. start: 在某個程序停止後。重新啟動它的輸出;
  7. stop:停止目前螢幕的輸出;
  8. susp:送出一個 terminal stop 的訊號給正在執行的程序;

萬用字元與特殊符號

常用的萬用字元有:

  • *:代表 0 到無窮多個任意字元。
  • ?:代表一定有一個任意的字元。
  • []:同樣代表一定有一個在中括號內的字元。
  • [-]:若有減號在中括號內時,代表在編碼順序內的所有字元。
  • []:若中括號內的第一個字元為指數符號(),那代表反向選擇。

常用特殊符號:

  • :批註符號,這個最常被使用在 script 中,視為說明。其後的資料均不執行。

  • \:轉義符號,將特殊字元或者萬用字元還原成一般字元。
  • |:管道,分隔兩個管道命令的界定。
  • ;:連續命令執行分隔符,連續性命令的界定。
  • ~:使用者的主資料夾。
  • $:使用變數前導符,即是變數之前需要加的變數替代值。
  • &:作業控制,將命令變成背景下工作。
  • !:邏輯運算意義上的 “非” 的意思。
  • /:目錄符號,路徑分隔的符號。
  • ,>>:資料流重定向,輸出導向,分別是 “替換” 與 “累加” 。

  • <,<<:資料流重定向,輸入導向。
  • '':單引號,不具有變數置換的功能。
  • "":具有變數置換的功能。
  • ``:兩個 “`” 中間為可以先執行的命令,也可以使用 $() 。
  • ():中間為子 shell 的起始和結束。
  • {}:在中間為命令塊的組合。

命令執行的判斷依據

有以下幾種情況:

  1. ;:從左到右依次執行指令,指令以 “;” 為分隔。
cmd;cmd
  1. $?與 && 或 ||:如果兩個命令之間具有相依性,而這個相依性主要判斷的地方就在於前一個命令執行的結果是否正確。如果前一個命令的執行結果正確,在 Linux 下面會回傳一個 $?=0 的值,再借助 “&&” 與 “||” 就能控制後續命令是否執行。
命令執行 說明
cmd1 && cmd2 若 cmd1 執行完畢且正確執行($?=0),則開始執行 cmd2;若 cmd1 執行完畢且為錯誤($?!=0),則 cmd2 不執行。
cmd1 || cmd2 若 cmd1 執行完畢且正確執行($?=0),則 cmd2 不執行;若 cmd1 執行完畢且為錯誤($?!=0),則開始執行 cmd2 。

管道命令

管道命令 “|” 僅能處理經由前面一個命令傳來的正確資訊,也就是 standard output 的資訊,對於 stadandard error 並沒有處理能力。
每個管道後面接的第一個資料必定是 “命令” ,而且這個命令必須要能夠接收 standard input 的資料才行,這樣的命令才可以是“管道命令”,例如 less,more,head,tail 等都是可以接收 standard input 的管道命令。至於 ls,cp,mv 等就不是管道命令了。因為 ls,cp,mv 並不會接收來自 stdin 的資料。也就是說:

  1. 管道僅會處理 standard output ,對於 standard error output 會予以忽略。
  2. 管道命令必須要能夠接收來自前一個命令的資料稱為 standard input 繼續處理才行。

shell script

shell script 是利用 shell 功能所寫的一個程式,這個程式是使用純文字檔案,將一些 shell 語法與命令(含外部命令)寫在裡面,搭配正則表示式、管道命令與資料流重定向等功能,以達到我們所想要的處理目的。編寫 shell scrpit 有以下注意事項:

  1. 命令的執行是從上而下的、從左而右地分析與執行;
  2. 命令、引數間的多個空白會被忽略掉;
  3. 空白行也將被忽略掉,並且 tab 按鍵所得的空白同樣視為空格鍵。
  4. 如果讀取到一個 Enter 符號,就嘗試開始執行該行命令;
  5. 可以使用 “[Enter]” 來擴充套件至下一行;
  6. “#” 可以作為批註。

編寫第一個 script

程式 “Hello World”

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo -e "Hello Wrold! \a \n"
exit 0

程式由以下幾部分組成:

  1. 第一行 “#!/bin/bash” 宣告這個 script 使用的 shell 名稱。
  2. 可以使用 “#” 寫上有關程式的註釋。
  3. 主要環境變數宣告。
  4. 主要程式部分。
  5. 告知執行結果。

script 的執行方式區別

不同的 script 執行方式會造成不一樣的結果。尤其是對 bash 的環境影響很大。

  1. 利用直接執行的方式來執行 scrpit。 scrpit 會使用一個新的 bash 環境來執行指令碼內的命令。也就是說,使用這種執行方式時,其實 scrpit 是在子程序的 bash 內執行的。這個問題的重點在於,子程序內的各項變數或操作將會結束而不會傳回到父程序中。
  2. 利用 source 命令執行指令碼。source 命令會在當前程序中執行指令碼,這樣各項操作都會在當前的 bash 內生效。

善用判斷式

比如:

test -e /dmtsai && echo "exist" || echo "Not exist"

最後結果就能告訴我們是 “exist” 還是 “Not exist”。

善用判斷符號

我們可以利用判斷符號 “[]” 來進行資料的判斷,比如想要知道 $HOME 這個變數是否為空,可以這樣寫:

[-z "$HOME" ] ; echo $?

條件判斷式

格式為:

if[條件判斷式]; then
      當條件成立時,執行的命令
fi

程式 sh02.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input (Y/N):"  yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
    echo "OK, continue"
    exit 0
fi

if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
    echo "Oh ,interrupt!"
    exit 0
fi
echo "I don't know what your choice is" && exit 0

利用 case……esac 判斷

格式為:

case $變數名稱 in
      "第一變數內容")
            程式段
            ;;
      "第二變數內容")
            程式段
            ;;
      *)
            不包含第一個變數內容和第二個變數內容的其他程式執行段
            exit 1
            ;;
esac

程式 sh03.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

case $1 in
    "hello")
        echo "Hello,how are you ?"
        ;;
    "")
        echo "You MUST input parameters, ex> {$0 someword}"
        ;;
    *)
        echo "Usage $0 {hello}"
        ;;
esac

利用 function

格式為:

function fname() {
      程式段
}

程式 sh04.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

function printit(){
    echo -n "Your choice is "
}

echo "This program will print your selection !"
case $1 in
    "one")
        printit; echo $1 | tr 'a-z' 'A-Z'
        ;;
    "two")
        printit; echo $1 | tr 'a-z' 'A-Z'
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac

迴圈

格式為:

while [condition]
do
      程式段落
done
until [condition]
do
      程式段落
done

程式 sh05.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

while [ "$yn" != "yes" -a "$yn" != "YES" ]
do
    read -p "Please input yes/YES to stop this program: " yn
done
echo "OK! you input the correct answer."

for...do..done(固定迴圈)

格式:

for var in con1 con2 con3 ...
do
      程式段
done

for((初始值;限制值;執行步長))
do
      程式段
done

程式 sh06.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

for animal in dog cat elephant
do
    echo "There are ${animal}s..."
done

程式 sh07.sh:

#!/bin/bash

PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input a number,I will count for 1+2+...+your_input: " nu

s = 0
for ((i=1; i<=$nu; i=i+1))
do
    s=$(($s+$i))
done

echo "The result of '1+2+3...+$nu' is ==> $s"

shell script 的追蹤與除錯

sh [-nvx] srcipts.sh

引數:

  • -n:不要執行 scrpit,僅查詢語法問題;
  • -v:在執行 script 之前,先將 scrpit 內容輸出到螢幕上;
  • -x:講使用到的 script 內容顯示到螢幕上;

內容來源

菜鳥教程-linux
《鳥哥的Linux私房菜》