1、什麼是shell?
其實在接觸linux之前我已經聽過shell的大名,當時周圍同學在聊shell編程,我對其一無所知。但令人驚奇的是,記憶力稱得上糟糕的我竟然記住了這個名詞。好了,廢話少說。在上一篇(一)Linux?
Ubuntu or CentOS? Linux安裝中,已經講述過。電腦使用者通過介面(shell,KDE等)與核心(Kernel)進行交流,以控制電腦硬體執行我們想要實現的功能。shell的字面意思是殼,也即包裹在核心(Kernel)外面的殼。是我們使用者用來與核心溝通的工具之一。
2、為什麼要學習shell?
現在linux做的相當人性化。例如ubuntu的視窗介面,已經能完成大部分使用者常用的操作。所以,為什麼還要學習shell呢?答:雖然基於X-window的操作介面已經相當完善,功能也相當強,但它們都只是將能利用到的軟體整合在一起的一組應用程式,並非是一個完整的套件。所以,當你升級其他套件的管理模組時,配置會很麻煩。甚至不同發布版本所設定的X-window介面也不相同,學習起來也有困擾。另外,當遠端連線時,文字介面的傳輸速度比較快。最重要的是:它可以讓你更深入瞭解linux。或許作為一般使用者只學習操作介面也能解決絕大多數問題,嘗嘗linux的鮮。但是作為系統管理者或者開發人員,學習shell是必要的。
3、Bash shell?
知道什麼是shell之後,大致瞭解一下shell的版本。具體的不再詳談,Unix中常見的shell一般有Bourne Shell(sh)、在sun裡預設的C Shell、商業上常用的K Shell和TCSH等。linux中使用的shell是Bourne Again Shell(簡稱Bash),它是Bourne Shell的增強版本,基於GNU架構發展而來。而在linux中可以使用哪些shell呢?目前Linux (以 CentOS 6.x 為例) 有多少我們可以使用的shell呢? 可以檢查一下 /etc/shells
這個檔案,發現有底下幾種可以用的 shell:
/bin/sh (已經被 /bin/bash 所取代)
/bin/bash (就是 Linux 預設的 shell)
/bin/tcsh (整合 C Shell ,提供更多的功能)
/bin/csh (已經被 /bin/tcsh 所取代)
既然有這麼多種shell,到底該學習哪一種呢?linux中預設的shell是Bash shell,所以我們先學好它就可以了。
4、Bash shell的功能
bash相容sh。主要功能有:
1)命令記憶功能。bash能記憶使用過的命令,只需要在命令列處按上下鍵就可以找到之前/後輸入的一個命令。在大多數發布版本中,預設的命令記憶功能可以記憶多達1000個命令。也即,你曾經下達過的命令幾乎都被記錄下來了。
這些命令都記錄在你的家目錄(/home/使用者名稱這個目錄)內的.bash_history檔案中。不過,~/.bash_history(~指家目錄,即/home/使用者名稱這個目錄。)記錄的是上一次登入時運行過的命令,本次登入輸入的命令則儲存在緩衝中,當登出系統後才會被記錄到~/.bash_history檔案中。
2)命令與檔案補全功能([tab]鍵的妙用)
命令與檔案補全功能可以讓你:少打很多字;確定輸入的資料正確。tab鍵的使用規則為:
[Tab] 接在一串命令的第一個字的後面,則為命令補全;
[Tab] 接在一串命令的第二個字以後時,則為檔案補齊。
指令補全:如果在執行命令的時不想按太多按鍵,例如指令pcprofiledump,如果你輸入了 pcprofile 之後,再按下 [Tab] 鍵,那麼 bash 馬上會自動的將後面的 dump 接上來!如果有重複的指令呢?按下兩次 [Tab] 將會列出所有重複的指令!
檔案名稱補全:如果你用 vi 來讀取某個檔案時,例如 /etc/man.config,當你輸入 vi /etc/man. 之後,直接按下 <tab> 鍵,則該檔案名稱就會被自動的補齊!
3)命令別名配置(alias)
假如我需要知道這個目錄底下的所有檔案 (包含隱藏檔) 及所有的檔案屬性,那麼我需要使用ls -al命令,稍微有些麻煩,有沒有更快的辦法?使用命令別名就可以。使用 alias將ls -al命令命名為lm,直接在bash中輸入lm就可替代ls -al命令。具體做法為:
alias lm='ls -al'
4)工作控制(jobs)、前景背景控制
這部分在之後的資源管理部分會詳細論述。使用前、背景的控制可以讓工作更為順利。工作控制(jobs)的可以讓我們隨時將工作丟到背景中執行,而不怕不小心使用了 Ctrl + C 停掉該程式。也可以在單使用者環境中,達到多任務的目的。
5)Shell scripts
不知道各位有沒有聽過批次檔,就是講一堆指令寫到一個檔案中。在 Linux 中的shell scripts功能則更為強大,可以將日常生活當中常需要下達的連續指令寫成一個檔案,該檔案可以通過互動方式來進行主機的偵測工作,也可以根據 shell 提供的環境變數及相關指令來進行設計,簡直就和程式設計語言的功能相當了。
萬用字元(Wildcard)
除了完整的字串之外,bash 還支援許多的萬用字元來協助使用者執行指令。例如,想知道 /usr/bin 目錄中有多少以 X 為開頭的檔案怎麼辦?執行ls -l /usr/bin/X* 命令就可以。此外,還有其他可供利用的萬用字元協助加快使用者的操作。
5、如何在Bash shell中下達指令?
command [-options] parameter1 parameter2 …即:命令 [-選項] 參數1 參數2 …
命令就是命令的名稱,比如改變所在目錄的命令cd;[]不實際出現,-出現,後面跟命令的選項。例如ls -al;參數即命令的參數。(註:命令太長時,可以使用\來延續指令到下一行)
6、變數與變數的設定
1)變數?
在輸入指令ls的時候,系統如何知道ls指令放在哪裡?這是因為有PATH變數,系統會通過這個變數中設定的路徑依次去尋找該指令,如果未找到,則會輸出command not found,如果找到,就執行指令。在寫一個script的時候,如果裡面有路徑,且在很多地方被使用,有修改需求時逐個修改會很麻煩,如果有了變數,則只需要修改變數值,其他地方因為引用的都是變數所以就無需再修改。所以,變數是一組文字或符號等,用來取代一些設定或一串保留的資料
2)echo
剛介紹了變數的概念,那如何顯示變數內容呢?使用echo指令。用法為echo $variable。例如echo $PATH
3)env
echo指令用來顯示變數內容,那麼我們如何知道系統中有哪些預設變數內容呢?使用env指令即可。
env是environment的簡寫,該指令將目前系統中的主要變數讀出來!但是,我們不是還可以自訂變數嗎?因此,除了 env 這個讀取環境變數的指令之外,還有一個可以將目前系統中所有的變數資料都讀出來的指令,稱為 set !set 除了會將上面的資料都讀出來之外,還會有額外的這些資訊也一起讀出(通常都與使用者的設定有關!)
4)set
註:由於系統中變數太多,所以上面的圖片只是env指令和set指令輸出結果的一部分
5)自訂變數
如何自訂變數呢?如果想讓該變數對所有使用者都有效,則需修改/etc/profile檔案,如果只想對當前使用者有效,則先切換到當前使用者的家目錄,然後修改.bashrc或.bash_profile檔案。在其中命名變數並對變數賦值
6)變數的命名規則
剛才說到命名變數,對變數命名有一定的規則,主要如下:
- 變數與變數內容以等號『=』來連結;
- 等號兩邊不能直接接空格符;
- 變數名稱只能是英文字母與數字,但是數字不能是開頭字元;
- 若有空格符可以使用雙引號『 " 』或單引號『 ' 』來將變數內容結合起來,但須要特別留意,雙引號內的特殊字元可以保有變數特性,但是單引號內的特殊字元則僅為一般字元;
- 必要時需要以跳脫字元『 \ 』來將特殊符號(如Enter, $, \, 空格符, '等)變成一般符號;
- 在一串指令中,還需要藉由其它的指令提供的資訊,可以使用 quote 『 ` command` 』;
- 若該變數為擴增變數內容時,則需以雙引號及 $變數名稱如:『 "$PATH":/home』繼續累加內容;
- 若該變數需要在其它子程式執行,則需要以 export 來使變數可以動作,如『export PATH』;
- 通常大寫字元為系統預設變數,自行設定變數可以使用小寫字元,方便判斷(純粹依照使用者興趣與嗜好);
- 取消變數的方法為:『unset 變數名稱』。
7)一般變數設定
1name=shan <=錯誤,因為變數開頭不能是數字
name = shan <=錯誤,因為等號兩邊不能直接接空格
name=shan <=正確
name=shan name <=錯誤,變數內容中有空格時,必須加雙引號
name="shan name" <=正確
name="shan's name" <=正確
8)變數累加設定
name=$nameaa <=錯誤,需要對原變數加雙引號
name="$name"aa <=正確,echo $name顯示shan's nameaa。
name="$name":aa <=正確
name="$name:aa" <=正確
9)變數延伸到子程式
name="shan's name"<= 設定name變數
echo $name <=顯示name變數內容
shan's name
/bin/bash <=開啟一個bash子程式
echo $name <=顯示name變數內容
<=會顯示Null 字元串,因為name不能使用在子程式
exit <=退出子程式的bash shell
export name <=這樣會將name變數延伸到子程式
10)指令中的指令
cd /lib/modules/`uname -r`/kernel
上式會限制性`uname -r`這個內嵌指令,然後將結果附加到整個指令中
11)取消變數設定:
unset name
12)在變數的設定中,單引號與雙引號有什麼不同呢?
答: 單引號與雙引號的最大不同在於雙引號仍然可以保有變數的內容,但單引號內僅能是一般字元,而不會有特殊符號。我們以底下的例子做說明:假設您定義了一個變數, name=shan ,現在想以 name 這個變數定義出 myname 顯示 shan is me 這個內容,要如何訂定呢?
[root @test root]# name=shan
[root @test root]# echo $name
VBird
[root @test root]# myname="$name is me"
[root @test root]# echo $myname
shan is me
[root @test root]# myname='$name is me'
[root @test root]# echo $myname
$name is me
13)使用了單引號的時候,那麼 $name 將失去原有的變數內容,僅為一般字元的顯示型態而已!這裡必需要特別小心在意!
例:在指令下達的過程中,quote ( ` )(註:非') 這個符號代表的意義為何?
答: 在一串指令中,在 ` 之內的指令將會被先執行,而其執行出來的結果將做為外部的輸入資訊!例如 uname –r 會顯示出目前的核心版本,而我們的核心版本在 /lib/modules 裡面,因此,你可以先執行 uname –r 找出核心版本,然後再以『 cd 目錄』到該目錄下,當然也可以執行
cd /lib/modules/`uname –r`直接到該目錄中。
14)變數的有效範圍:
『變數的設定只在目前這個 shell 環境當中存在,在下個或者是在子程式中 ( 子 shell ) 將不會存在!』要讓變數在下個程式也可以繼續的使用,需要使用 export 這個命令!此外,其實除了 shell 的父、子程式外,在指令碼( scripts )的編寫當中,由於有的軟體會使用到 2 個以上的 scripts 做為一個完整的套件!也就是說,假如你有兩支程式,一支為 scripts1.sh 以及 scripts2.sh ,而 scripts2.sh 會去引用 scripts1.sh 的變數,在 scripts1.sh
當中設定的變數請『千萬記得以 export 設定』,否則你的變數將無法在兩個 scripts 之間互相被引用!當這個 scripts 執行完畢之後,剛剛在 scripts 當中設定的變數也就『失效』。
15)read,array,eval
使用read指令可以動態設定指令內容,而不是靜態設定好再使用。
read 變數名,斷行符號後會等待使用者輸入變數內容,例如輸入read name[斷行符號],再輸入shan,再使用echo $name,輸出結果為shan。
array制定一個變數數組,而eval則可以使用變數的變數。例如
day=2
year=day
echo \$$year <=\為逸出字元,即將\後面的第一個$改變為一般字元
$day
eval echo \$$year <=加上eval後,\$$year的變為一個變數(即$day)
2
16)history、!number與!command
使用history命令可以查看過去輸入的指令。輸出的內容為:編號 指令名。如:66 ls -al。此時,我可以使用!66來執行ls -al指令,也可以使用!ls來執行ls -al指令。number為指令的序號,command為指令前幾個字母。如果輸入!!,則表示執行上一個指令(剛輸入的那個指令)
7、Bash shell的設定檔案
1)系統設定值:也即每個使用者進入bash shell後,會先讀取的設定檔案。主要有以下幾個:
/etc/profile:設定了幾個重要的變數,如PATH,USER,MAIL,HOSTNAME,HISTSIZE,umask等。除此之外還有/etc/bashrc和/etc/man.config檔案,具體內容可以百度或Google。
2)個人設定值:就是只針對當前使用者自己的檔案。即在個人家目錄中的幾個隱藏檔案。主要有:
~/.bash_profile:定義了個人路徑與環境變數。可以在這裡修改你的個人路徑,也可以在 ~/.bashrc 這個個人設定的變數裡頭修改。
~/.bash_history:這個檔案的用途在於將你曾經使用過的命令記錄下來,而當你再次的以上下鍵搜尋或者直接以 history 搜尋的時候,就可以找到曾經使用過的指令。
~/.bash_logout:裡面定義你登出 shell 的時候, BASH 會為你所做的事情!通常預設是只有 clear 清除螢幕這件事情而已。
8、source
如果我需要將目前的設定檔的內容讀入一次,需要重新 logout 再 login 才能夠讀入,那麼有沒有辦法不登出而直接讀入變數設定檔案呢?當然可以,就使用 source 即可!具體格式為:source 變數設定檔案
9、萬用字元與特殊符號
符號內容*萬用字元,代表一個或多個字元(或數字)?萬用字元,代表一個字母#批註,這個最常被使用在 script 當中,視為說明!\跳脫符號,將『特殊字元或萬用字元』還原成一般字元|分隔兩個管線命令的界定;;連續性命令的界定(注意!與管線命令並不相同)~使用者的家目錄$亦即是變數之前需要加的變數取代值&將指令變成背景下工作!邏輯運算意義上的『非』 not 的意思!/路徑分隔的符號>, >>輸出導向,分別是『取代』與『累加』'單引號,不具有變數置換的功能"具有變數置換的功能!` `兩個『 ` 』中間為可以先執行的指令!( )在中間為子 shell 的起始與結束[ ]在中間為字元的組合{ }在中間為命令區塊的組合!組合按鍵執行結果Ctrl + C終止目前的命令Ctrl + D輸入結束(EOF),例如郵件結束的時候;Ctrl + M就是 Enter 啦!Ctrl + S暫停螢幕的輸出Ctrl + Q恢複螢幕的輸出Ctrl + U在提示字元下,將整列命令刪除Ctrl + Z『暫停』目前的命令
10、連續指令的下達方式:
兩個指令先後寫在一起,可以用以下三種方式寫:
command1; command2。代表不論 command1執行結果為何,command2 都會被執行!
command1 && command2。代表如果command1沒有錯誤,command2才會執行
command1 || command2。代表如果command1有錯誤,command2才會執行
11、絕對路徑與相對路徑
以/開頭的路徑為絕對路徑,不以/開頭的路徑為相對路徑。另外,'.'表示本層目錄,‘..’表示上層目錄,'~'表示家目錄。
註:檔案名稱前加'.'表示該檔案為隱藏檔案。
12、命令重導向
命令重導向:就是將你目前的所得資料儲存到一個指定地方!最常用的,是將目前的螢幕輸出資料轉到檔案中,可以這麼寫:ls -l / > test ,符號 > 就是將輸出結果導向到 test 這個檔案中的意思。
如果你只執行ls -l / ,螢幕會將根目錄的檔案與目錄都列出在螢幕上;但是當使用 > 導向到 test 這個檔案中時,則螢幕不會顯示任何訊息,但是會將剛剛你執行的結果輸出到 test 這個檔案中。
註:重導向時,若該檔案(就是 test )若不存在,系統會自動建立,如果當這個檔案存在,那麼系統就會先將這個檔案內容清空,然後再將資料寫入!
除了這個 > 的符號之外,在 bash 命令執行的過程中,主要有三種輸出入的狀況,分別是:
標準輸入;代碼為 0 ;或稱為 stdin ;使用的方式為 <
標準輸出:代碼為 1 ;或稱為 stdout;使用的方式為 1>
錯誤輸出:代碼為 2 ;或稱為 stderr;使用的方式為 2>
基本的指令書寫方式為:
這裡我們來說明一下命令重導向裡面幾個常用的符號與裝置:
< :由 < 的右邊讀入參數檔案;
> :將原本由螢幕輸出的正確資料輸出到 > 右邊的 file ( 檔案名稱 ) 或 device ( 裝置,如 printer )去;
>> :將原本由螢幕輸出的正確資料輸出到 >> 右邊,與 > 不同的是,該檔案將不會被覆蓋,而新的資料將以『增加的方式』增加到該檔案的最後面;
2> :將原本應該由螢幕輸出的錯誤資料輸出到 2> 的右邊去。
/dev/null :可以說成是黑洞裝置!
例如:
ls -al 1> list.txt 2> error.txt
將顯示資料,正確的輸出到list.txt,錯誤的輸出到error.txt
ls -al 1> list.txt 2>&1
將顯示的資料,無論正確或錯誤均輸出到list.txt中
註:ls -al 1> list.txt 2> list.txt是錯誤的寫法。
13、管道命令 ( pipe )
bash 命令執行的時候有輸出的資料會出現!那麼如果這群資料必需要經過幾道手續之後才能得到我們所想要的格式,應該如何來設定?這就牽涉到逛到命令的問題了( pipe ),管道命令使用的是『 | 』這個界定符號!另外,管道命令與『連續下達命令』是不一樣的,這點底下我們會再說明。底下我們先舉一個例子來說明一下簡單的管線命令。
假設我們要讀取 last 這個指令中,那個 root 登入的『次數』應該怎麼做?我們只需要『次數』。那麼我所進行的步驟是:
執行 last ,將所有這個月的所有人登入資料取出來;
使用 grep 將上面的輸出資料(stdout)當中的 root 擷取出來,其它的不要;
使用 wc 這個可以計算行數的指令將上一步的資料計算行數!
由於 last 的輸出是一行代表一次登入,所以只要計算幾行就代表登入幾次的意思,所以囉!經由上面三個步驟,將 last 資料逐步的篩選,就可以得到我們的資料了!整個命令可以寫成如下:
last
last | grep root
last | grep root | wc -l
你可以分別執行『 last 』然後再逐步增加為『 last | grep root 』,最後到上面那一行,那麼就馬上可以清楚的知道為何會這麼做囉!這個管線命令『 | 』僅能處理經由前面一個指令傳來的正確資訊,也就是 standard output ( STDOUT ) 的資訊,對於 stdandard error 並沒有直接處理的能力,請記得。那麼整體的管線命令可以使用表示之:
在每個管線的部分都是『指令』呢!而後一個指令的輸入乃是由前一個指令的輸出而來的!
下面我們來談一談一些基本的管線命令指令介紹:
1)cut
主要用於將同一行的資料進行分割,命令格式為:cut [-dcf] fields
參數說明:
-d:後面接的是用來分割的字元,預設為空白格符
-c:後面接的是第幾個字元
-f:後面接的是第幾個區塊
2)sort
主要用於對資料進行排序,命令格式為:sort [-t 分隔字元] [(+起始)(-結束)] [-nru]
參數說明:
-t 分隔字元:使用分隔字元來隔開不同區間,預設是tab
+start -end:由第start區間排序到end區間
-n:用純數字排序,否則就會以文字形態排序
-r:反向昂排序
-u:相同出現的一行,只列出一次
3)wc
主要用於計算檔案內容,命令格式為:wc [-lmw]
參數說明:
-l:多少行
-m:多少字元
-w:多少字
4)uniq
重複的行刪除掉只顯示一個
5)tee
在命令重導向的時候,如果將資料輸出到檔案中,螢幕上就不會顯示任何資料,如果需要在螢幕上也顯示資料,加上tee就可以。
6)tr
在Regex中用的比較多。Regex在後面會講。tr [-ds] set1
參數說明:
-d:刪除set1這個字串
-s:取代掉重複的字元
7)split
用來分割檔案。具體格式為:split [-bl] 輸入檔案 輸出檔案前置字元
參數說明:
-b:以檔案size來分
-l:以行數來分
寫在末尾的一些話:
完整的Bash shell應該包括shell script,先寫完這部分吧。寫部落格耗費的時間比看書多的多,不過寫出來是一種總結。所以還是寫一寫的好~
轉載請註明出處:http://blog.csdn.net/iAm333