shell腳本編寫筆記

包含轉載內容,轉載自http://wenku.baidu.com/link?url=jtCHxEYzgGve6P64U3JRQRgU6nhpGvqFLLpWu9I2Htq6hi9TGLudRFkk7rJlzYt-3S-39oMAViQQ8oHDQMdBumP3MyIaxUFmo7ZH-6b0J37 html

一 .shell簡介java

Shell不只是命令的收集,更是一門很是棒的編程語言。能夠經過使用shell使大量的任務自動化,shell特別擅長系統管理任務,尤爲適合那些易用性、可維護性和便攜性比效率更重要的任務。 其實做爲命令語言交互式地解釋和執行用戶輸入的命令只是shell功能的一個方面,shell還能夠用來進行程序設計,它提供了定義變量和參數的手段以及豐富的程序控制結構。使用shell編程相似於DOS中的批處理文件,稱爲shell script,又叫shell程序或shell命令文件。linux

 二.幾種流行的shell  ios

目前流行的shell有ash、bash、ksh、csh、zsh等,你能夠用下面的命令來查看你本身的shell類型:  #echo $SHELL   $SHELL是一個環境變量,它記錄用戶所使用的shell類型。你能夠用命令:  #shell-name   來轉換到別的shell,這裏shell-name是你想要嘗試使用的shell的名稱,如ash等。這個命令爲用戶又啓動了一個shell,這個shell在最初登陸的那個shell以後,稱爲下級的shell或子shell。使用命令:  $exit   能夠退出這個子shell。正則表達式

 

三.shell基本語法  shell

shell的基本語法主要就是如何輸入命令運行程序以及如何在程序之間經過shell的一些參數提供便利手段來進行通信。express

(1)輸入輸出重定向  編程

在Linux中,每個進程都有三個特殊的文件描述指針:標準輸入(standard input,文件描述指針爲0)、標準輸出(standard output,文件描述指針爲1)、標準錯誤輸出(standard error,文件描述指針爲2)。這三個特殊的文件描述指針使進程在通常狀況下接收標準輸入終端的輸入,同時由標準終端來顯示輸出,Linux同時也向使用者提供可使用普通的文件或管道來取代這些標準輸入輸出設備。在shell中,使用者能夠利用「>」和「<」來進行輸入輸出重定向。如:  vim

command>file:將命令的輸出結果重定向到一個文件。  bash

command>&file:將命令的標準錯誤一塊兒輸出重定向到一個文件。  

command>>file:將標準輸出的結果追加到文件中。   command>>&file:將標準輸出和標準錯誤輸出的結構都追加到文件中。  

(2)管道pipe  

pipe一樣能夠在標準輸入輸出和標準錯誤輸出間作代替工做,這樣一來,能夠將某一個程序的輸出送到另外一個程序的輸入,其語法以下:

command1| command2[| command3...]

 也能夠連同標準錯誤輸出一塊兒送入管道:  command1| &command2[|& command3...]  

(3)前臺和後臺  

在shell下面,一個新產生的進程能夠經過用命令後面的符號「;」和「&」來分別之前臺和後臺的方式來執行,語法以下:  

command   產生一個前臺的進程,下一個命令須等該命令運行結束後才能輸入。

command &   產生一個後臺的進程,此進程在後臺運行的同時,能夠輸入其餘的命令。  

四 .shell程序的變量和參數  

像高級程序設計語言同樣,shell也提供說明和使用變量的功能。對shell來說,全部變量的取值都是一個字符串,shell程序採用$var的形式來引用名爲var的變量的值。

Shell有如下幾種基本類型的變量:

(1)shell定義的環境變量
shell在開始執行時就已經定義了一些和系統的工做環境有關的變量,這些變量用戶還能夠從新定義,經常使用的shell環境變量有:

HOME:用於保存註冊目錄的徹底路徑名。

PATH:用於保存用冒號分隔的目錄路徑名,shell將按PATH變量中給出的順序搜索這些目錄,找到的第一個與命令名稱一致的可執行文件將被執行。

TERM:終端的類型。

UID:當前用戶的標識符,取值是由數字構成的字符串。

PWD:當前工做目錄的絕對路徑名,該變量的取值隨cd命令的使用而變化。

PS1:主提示符,在特權用戶下,缺省的主提示符是「#」,在普通用戶下,缺省的主提示符是「$」。

PS2:在shell接收用戶輸入命令的過程當中,若是用戶在輸入行的末尾輸入「\」而後回車,或者當用戶按回車鍵時shell判斷出用戶輸入的命令沒有結束時,顯示這個輔助提示符,提示用戶繼續輸入命令的其他部分,缺省的輔助提示符是「>」。

(2)用戶定義的變量

用戶能夠按照下面的語法規則定義本身的變量: 變量名=變量值

要注意的一點是,在定義變量時,變量名前不該加符號「$」,在引用變量的內容時則應在變量名前加「$」;

在給變量賦值時,等號兩邊必定不能留空格,若變量中自己就包含了空格,則整個字符串都要用雙引號括起來。 在編寫shell程序時,爲了使變量名和命令名相區別,建議全部的變量名都用大寫字母來表示。 有時咱們想要在說明一個變量並對它設定爲一個特定值後就不在改變它的值,這能夠用下面的命令來保證一個變量的只讀性:

readly 變量名

在任什麼時候候,創建的變量都只是當前shell的局部變量,因此不能被shell運行的其餘命令或shell程序所利用,export命令能夠將一局部變量提供給shell執行的其餘命令使用,其格式爲:

export 變量名

也能夠在給變量賦值的同時使用export命令: export 變量名=變量值

使用export說明的變量,在shell之後運行的全部命令或程序中均可以訪問到。

(3)位置參數

位置參數是一種在調用shell程序的命令行中按照各自的位置決定的變量,是在程序名以後輸入的參數。位置參數之間用空格分隔,shell取第一個位置參數替換程序文件中的$1,第二個替換$2,依次類推。

$0是一個特殊的變量,它的內容是當前這個shell程序的文件名,因此,$0不是一個位置參數,在顯示當前全部的位置參數時是不包括$0的。

(4)預約義變量

預約義變量和環境變量相相似,也是在shell一開始時就定義了的變量,所不一樣的是,用戶只能根據shell的定義來使用這些變量,而不能重定義它。全部預約義變量都是由$符和另外一個符號組成的,經常使用的shell預約義變量有:

$#:位置參數的數量

$*:全部位置參數的內容

$?:命令執行後返回的狀態

$$:當前進程的進程號
$!:後臺運行的最後一個進程號

$0:當前執行的進程名

其中,「$?」用於檢查上一個命令執行是否正確(在Linux中,命令退出狀態爲0表示該命令正確執行,任何非0值表示命令出錯)。

「$$」變量最多見的用途是用做臨時文件的名字以保證臨時文件不會重複。

(5)參數置換的變量

shell提供了參數置換能力以便用戶能夠根據不一樣的條件來給變量賦不一樣的值。參數置換的變量有四種,這些變量一般與某一個位置參數相聯繫,根據指定的位置參數是否已經設置類決定變量的取值,它們的語法和功能分別以下:

a. 變量=${參數-word}:若是設置了參數,則用參數的值置換變量的值,不然用word置換。即這種變量的值等於某一個參數的值,若是該參數沒有設置,則變量就等於word的值。

b. 變量=${參數=word}:若是設置了參數,則用參數的值置換變量的值,不然把變量設置成word而後再用word替換參數的值。注意,位置參數不能用於這種方式,由於在shell程序中不能爲位置參數賦值。

c. 變量=${參數?word}:若是設置了參數,則用參數的值置換變量的值,不然就顯示word並從shell中退出,若是省略了word,則顯示標準信息。這種變量要求必定等於某一個參數的值,若是該參數沒有設置,就顯示一個信息,而後退出,所以這種方式經常使用於出錯指示。

d. 變量=${參數+word}:若是設置了參數,則用word置換變量,不然不進行置換。 全部這四種形式中的「參數」既能夠是位置參數,也能夠是另外一個變量,只是用位置參數的狀況比較多。

 

 

五.shell程序設計的流程控制

和其餘高級程序設計語言同樣,shell提供了用來控制程序執行流程的命令,包括條件分支和循環結構,用戶能夠用這些命令創建很是複雜的程序。  

與傳統的語言不一樣的是,shell用於指定條件值的不是布爾表達式而是命令和字符串。  

1.test測試命令  

test命令用於檢查某個條件是否成立,它能夠進行數值、字符和文件三個方面的測試,其測試符和相應的功能分別以下:  

(1)數值測試:  

-eq:等於則爲真  

-ne:不等於則爲真  

-gt:大於則爲真  

-ge:大於等於則爲真  

-lt:小於則爲真  

-le:小於等於則爲真  

(2)字符串測試:  

=:等於則爲真  

!=:不相等則爲真  

-z 字符串:字符串長度僞則爲真  

-n 字符串:字符串長度不僞則爲真  

(3)文件測試:  

-e 文件名:若是文件存在則爲真  

-r 文件名:若是文件存在且可讀則爲真  

-w 文件名:若是文件存在且可寫則爲真

-x 文件名:若是文件存在且可執行則爲真  

-s 文件名:若是文件存在且至少有一個字符則爲真  

-d 文件名:若是文件存在且爲目錄則爲真  

-f 文件名:若是文件存在且爲普通文件則爲真  

-c 文件名:若是文件存在且爲字符型特殊文件則爲真  

-b 文件名:若是文件存在且爲塊特殊文件則爲真  

另外,Linux還提供了與(「!」)、或(「-o)、非(「-a」)三個邏輯操做符用於將測試條件鏈接起來,其優先級爲:「!」最高,「-a」次之,「-o」最低。  同時,bash也能完成簡單的算術運算,格式以下:  

$[expression]  

例如:var1=2  var2=$[var1*10+1]  則:var2的值爲21。  

2.if條件語句  

shell程序中的條件分支是經過if條件語句來實現的,其通常格式爲:

 if 條件命令串  then  

    條件爲真時的命令串  

else  

    條件爲假時的命令串  

fi  

3.for 循環  

for循環對一個變量的可能的值都執行一個命令序列。賦給變量的幾個數值既能夠在程序內以數值列表的形式提供,也能夠在程序之外以位置參數的形式提供。for循環的通常格式爲:  

for 變量名 [in 數值列表]

   do  

   若干個命令行  

done  

變量名能夠是用戶選擇的任何字符串,若是變量名是var,則在in以後給出的數值將順序替換循環命令列表中的$var。若是省略了in,則變量var的取值將是位置參數。對變量的每個可能的賦值都將執行do和done之間的命令列表。  

4.while和until 循環  

while 和 until命令都是用命令的返回狀態值來控制循環的。

While 循環的通常格式爲:  

  while  

  若干個命令行1  

  do   若干個命令行2  

  done  

只要while的「若干個命令行1」中最後一個命令的返回狀態爲真,while循環就繼續執行do...done之間的「若干個命令行2」。  

until命令是另外一種循環結構,它和while命令類似,其格式以下:  

until   若干個命令行1 

do  

若干個命令行2  

done  

until循環和while循環的區別在於:while循環在條件爲真時繼續執行循環,而until則是在條件爲假時繼續執行循環。  

Shell還提供了true和false兩條命令用於創建無限循環結構的須要,它們的返回狀態分別是總爲0或總爲非0  

5.case 條件選擇  

if條件語句用於在兩個選項中選定一項,而case條件選擇爲用戶提供了根據字符串或變量的值從多個選項中選擇一項的方法,其格式以下:

 case string in  

exp-1)  若干個命令行1  ;;  

exp-2)   若干個命令行2  ;;

 „„  *)   其餘命令行

esac  

shell經過計算字符串string的值,將其結果依次和表達式exp-一、exp-2等進行比較,直到找到一個匹配的表達式爲止,若是找到了匹配項則執行它下面的命令直到遇到一對分號(;;)爲止。   在case表達式中也可使用shell的通配符(「*」、「?」、「[ ]」)。一般用「*」做爲case命令的最後表達式以便使在前面找不到任何相應的匹配項時執行「其餘命令行」的命令。  

6.無條件控制語句break和continue  

break 用於當即終止當前循環的執行,而contiune用於不執行循環中後面的語句而當即開始下一個循環的執行。這兩個語句只有放在do和done之間纔有效。  

7.函數定義  

在shell中還能夠定義函數。函數實際上也是由若干條shell命令組成的,所以它與shell程序形式上是類似的,不一樣的是它不是一個單獨的進程,而是shell程序的一部分。函數定義的基本格式爲:  

functionname  

{  

若干命令行  

}  

調用函數的格式爲:  

functionname param1 param2 „„  

shell函數能夠完成某些例行的工做,並且還能夠有本身的退出狀態,所以函數也能夠做爲if、while等控制結構的條件。  在函數定義時不用帶參數說明,但在調用函數時能夠帶有參數,此時shell將把這些參數分別賦予相應的位置參數$一、$二、...及$*。

8.命令分組

在shell中有兩種命令分組的方法:「()」和「{}」,前者當shell執行()中的命令時將再建立一個新的子進程,而後這個子進程去執行圓括弧中的命令。當用戶在執行某個命令時不想讓命令運行時對狀態集合(如位置參數、環境變量、當前工做目錄等)的改變影響到下面語句的執行時,就應該把這些命令放在圓括弧中,這樣就能保證全部的改變只對子進程產生影響,而父進程不受任何干擾;

{}用於將順序執行的命令的輸出結果用於另外一個命令的輸入(管道方式)。當咱們要真正使用圓括弧和花括弧時(如計算表達式的優先級),則須要在其前面加上轉義符(\)以便讓shell知道它們不是用於命令執行的控制所用。

9.信號

trap命令用於在shell程序中捕捉到信號,以後能夠有三種反應方式:

(1)執行一段程序來處理這一信號

(2)接受信號的默認操做

(3)忽視這一信號

trap對上面三種方式提供了三種基本形式:

第一種形式的trap命令在shell接收到signal list清單中數值相同的信號時,將執行雙引號中的命令串。

trap 'commands' signal-list

trap "commands" signal-list

爲了恢復信號的默認操做,使用第二種形式的trap命令:

trap signal-list

第三種形式的trap命令容許忽視信號: trap " " signal-list

注意:

(1)對信號11(段違例)不能捕捉,由於shell自己須要捕捉該信號去進行內存的轉儲。

(2)在trap中能夠定義對信號0的處理(實際上沒有這個信號),shell程序在其終止(如執行exit語句)時發出該信號。

(3)在捕捉到signal-list中指定的信號並執行完相應的命令以後,若是這些命令沒有將shell程序終止的話,shell程序將繼續執行收到信號時所執行的命令後面的命令,這樣將很容易致使shell程序沒法終止。

另外,在trap語句中,單引號和雙引號是不一樣的,當shell程序第一次碰到trap語句時,將把commands中的命令掃描一遍。此時若commands是用單引號括起來的話,那麼shell不會對commands中的變量和命令進行替換,不然commands中的變量和命令將用當時具體的值來替換。

6、運行shell程序的方法

用戶能夠用任何編輯程序來編寫shell程序。由於shell程序是解釋執行的,因此不須要編譯裝配成目標程序,按照shell編程的慣例,以bash爲例,程序的第一行通常爲「#!/bin/bash」,其中#表示該行是註釋,歎號「!」告訴shell運行歎號以後的命令並用文件的其他部分做爲輸入,也就是運行/bin/bash並讓/bin/bash去執行shell程序的內容。

執行shell程序的方法有三種:

(1)sh shell程序文件名

這種方法的命令格式爲: bash shell程序文件名

這其實是調用一個新的bash命令解釋程序,而把shell程序文件名做爲參數傳遞給它。新啓動的shell將去讀指定的文件,執行文件中列出的命令,當全部的命令都執行完結束。該方法的優勢是能夠利用shell調試功能。

(2)sh格式爲: bash這種方式就是利用輸入重定向,使shell命令解釋程序的輸入取自指定的程序文件。

(3)用chmod命令使shell程序成爲可執行的

一個文件可否運行取決於該文件的內容自己可執行且該文件具備執行權。對於shell程序,當用編輯器生成一個文件時,系統賦予的許可權限都是644(rw-r-r--),所以,當用戶須要運行這個文件時,只須要直接鍵入文件名便可。

在這三種運行shell程序的方法中,最好按下面的方式選擇:當剛創建一個shell程序,對它的正確性尚未把握時,應當使用第一種方式進行調試。當一個shell程序已經調試好時,應使用第三種方式把它固定下來,之後只要鍵入相應的文件名便可,並可被另外一個程序所調用。

7、bash程序的調試

在編程過程當中不免會出錯,有的時候,調試程序比編寫程序花費的時間還要多,shell程序一樣如此。

shell程序的調試主要是利用bash命令解釋程序的選擇項。

調用bash的形式是: bash -選擇項 shell程序文件名

幾個經常使用的選擇項是:

-e:若是一個命令失敗就當即退出

-n:讀入命令可是不執行它們

-u:置換時把未設置的變量看做出錯

-v:當讀入shell輸入行時把它們顯示出來

-x:執行命令時把命令和它們的參數顯示出來

上面的全部選項也能夠在shell程序內部用「set -選擇項」的形式引用,而「set +選擇項」則將禁止該選擇項起做用。若是隻想對程序的某一部分使用某些選擇項時,則能夠將該部分用上面兩個語句包圍起來。

1.未置變量退出和當即退出 未置變量退出特性容許用戶對全部變量進行檢查,若是引用了一個未賦值的變量就終止shell程序的執行。shell一般容許未置變量的使用,在這種狀況下,變量的值爲空。若是設置了未置變量退出選擇項,則一旦使用了未置變量就顯示錯誤信息,並終止程序的運行。未置變量退出選擇項爲「-u」。 當shell運行時,若遇到不存在或不可執行的命令、重定向失敗或命令非正常結束等狀況時,若是未經從新定向,該出錯信息會打印在終端屏幕上,而shell程序仍將繼續執行。要想在錯誤發生時迫使shell程序當即結束,可使用「-e」選項將shell程序的執行當即終止。

2.shell程序的跟蹤 調試shell程序的主要方法是利用shell命令解釋程序的「-v」或「-x」選項來跟蹤程序的執行。「-v」選擇項使shell在執行程序的過程當中,把它讀入的每個命令行都顯示出來,而「-x」選擇項使shell在執行程序的過程當中把它執行的每個命令在行首用一個「+」加上命令名顯示出來。並把每個變量和該變量所取的值也顯示出來,所以,它們的主要區別在於:在執行命令行以前無「-v」則打印出命令行的原始內容,而有「-v」則打印出通過替換後的命令行的內容。 除了使用shell的「-v」和「-x」選擇項之外,還能夠在shell程序內部採起一些輔助調試的措施。例如,能夠在shell程序的一些關鍵地方使用echo命令把必要的信息顯示出來,它的做用至關於C語言中的printf語句,這樣就能夠知道程序運行到什麼地方及程序目前的狀態。

8、bash的內部命令  

bash命令解釋程序包含了一些內部命令。內部命令在目錄列表時是看不見的,它們由shell自己提供。

經常使用的內部命令有:echo、eval、exec、export、readonly、read、shift、wait和點(.)。

下面簡單介紹其命令格式和功能。  

1.echo  

命令格式:echo arg  

功能:在屏幕上打印出由arg指定的字符串。

 2.eval  

命令格式:eval args  

功能:當shell程序執行到eval語句時,shell讀入參數args,並將它們組合成一個新的命令,而後執行。

 3.exec  

命令格式:exec 命令 命令參數  

功能:當shell執行到exec語句時,不會去建立新的子進程,而是轉去執行指定的命令,當指定的命令執行完時,該進程,也就是最初的shell就終止了,因此shell程序中exec後面的語句將再也不被執行。  

4.export  

命令格式:export 變量名 或:export 變量名=變量值  

功能:shell能夠用export把它的變量向下帶入子shell從而讓子進程繼承父進程中的環境變量。但子shell不能用export把它的變量向上帶入父shell。   注意:不帶任何變量名的export語句將顯示出當前全部的export變量。  

5.readonly  

命令格式:readonly 變量名  

功能:將一個用戶定義的shell變量標識爲不可變的。不帶任何參數的readonly命令將顯示出全部只讀的shell變量。

 6.read  

命令格式:  read變量名錶  

功能:從標準輸入設備讀入一行,分解成若干字,賦值給shell程序內部定義的變量。

 7.shift語句  

功能:shift語句按以下方式從新命名全部的位置參數變量:$2成爲$1,$3成爲$2„„在程序中每使用一次shift語句,都使全部的位置參數依次向左移動一個位置,並使位置參數「$#」減一,直到減到0。  

8.wait   功能:是shell等待在後臺啓動的全部子進程結束。Wait的返回值老是真。  

9.exit   功能:退出shell程序。在exit以後可有選擇地指定一個數字做爲返回狀態。  

10.「.」(點)   命令格式:. Shell程序文件名   功能:使shell讀入指定的shell程序文件並依次執行文件中的全部語句。

 

Linux 腳本編寫基礎

1.1.1 開頭

程序必須如下面的行開始(必須方在文件的第一行):

#!/bin/sh

符號#!用來告訴系統它後面的參數是用來執行該文件的程序。在這個例子中咱們使用/bin/sh來執行程序。 當編輯好腳本時,若是要執行該腳本,還必須使其可執行。 要使腳本可執行:

編譯 chmod +x filename

這樣才能用./filename 來運行

1.1.2 註釋 在進行shell編程時,以#開頭的句子表示註釋,直到這一行的結束。咱們真誠地建議您在程序中使用註釋。 若是您使用了註釋,那麼即便至關長的時間內沒有使用該腳本,您也能在很短的時間內明白該腳本的做用及工做原理。

1.1.3 變量 在其餘編程語言中您必須使用變量。在shell編程中,全部的變量都由字符串組成,而且您不須要對變量進行聲明。要賦值給一個變量,您能夠這樣寫: #!/bin/sh

#對變量賦值:

a="hello world"

# 如今打印變量a的內容:

echo "A is:" echo $a

有時候變量名很容易與其餘文字混淆,好比:

num=2

echo "this is the $numnd" 這並不會打印出"this is the 2nd",而僅僅打印"this is the ",由於shell會去搜索變量numnd的值,可是這個變量時沒有值的。可使用花括號來告訴shell咱們要打印的是num變量:

num=2 echo "this is the ${num}nd"

這將打印: this is the 2nd

1.1.4 環境變量

由export關鍵字處理過的變量叫作環境變量。咱們不對環境變量進行討論,由於一般狀況下僅僅在登陸腳本中使用環境變量。

1.1.5 Shell命令和流程控制

在shell腳本中可使用三類命令:

1)Unix 命令: 雖然在shell腳本中可使用任意的unix命令,可是仍是由一些相對更經常使用的命令。這些命令一般是用來進行文件和文字操做的。

經常使用命令語法及功能

echo "some text": 將文字內容打印在屏幕上

ls: 文件列表 wc –l filewc -w filewc -c file: 計算文件行數計算文件中的單詞數計算文件中的字符數

cp sourcefile destfile: 文件拷貝

mv oldname newname : 重命名文件或移動文件

rm file: 刪除文件

grep 'pattern' file: 在文件內搜索字符串好比:grep 'searchstring' file.txt

cut -b colnum file: 指定欲顯示的文件內容範圍,並將它們輸出到標準輸出設備

好比:輸出每行第5個到第9個字符cut -b5-9 file.txt

千萬不要和cat命令混淆, 這是兩個徹底不一樣的命令 cat file.txt: 輸出文件內容到標準輸出設備(屏幕)上

file somefile: 獲得文件類型

read var: 提示用戶輸入,並將輸入賦值給變量

sort file.txt: 對file.txt文件中的行進行排序

uniq: 刪除文本文件中出現的行列好比: sort file.txt | uniq

expr: 進行數學運算Example: add 2 and 3expr 2 "+" 3

find: 搜索文件好比:根據文件名搜索find . -name filename -print

tee: 將數據輸出到標準輸出設備(屏幕) 和文件好比:somecommand | tee outfile basename file: 返回不包含路徑的文件名好比:

basename /bin/tux將返回 tux

dirname file: 返回文件所在路徑好比:dirname /bin/tux將返回 /bin

head file: 打印文本文件開頭幾行

tail file : 打印文本文件末尾幾行

sed: Sed是一個基本的查找替換程序。能夠從標準輸入(好比命令管道)讀入文本,並將 結果輸出到標準輸出(屏幕)。該命令採用正則表達式(見參考)進行搜索。不要和shell中的通配符相混淆。好比:將linuxfocus 替換爲LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file awk: awk 用來從文本文件中提取字段。缺省地,字段分割符是空格,可使用-F指定其餘分割符。

cat file.txt | awk -F, '{print $1 "," $3 }'這裏咱們使用,做爲字段分割符,同時打印第一個和第三個字段。若是該文件內容以下: Adam Bor, 34, IndiaKerry Miller, 22, USA命令輸出結果爲:Adam Bor, IndiaKerry Miller, USA 2) 概念: 管道, 重定向和 backtick 這些不是系統命令,可是他們真的很重要。

管道 (|)

將一個命令的輸出做爲另一個命令的輸入。 grep "hello" file.txt | wc -l 在file.txt中搜索包含有」hello」的行並計算其行數。 在這裏grep命令的輸出做爲wc命令的輸入。固然您可使用多個命令。

重定向:將命令的結果輸出到文件,而不是標準輸出(屏幕)。

> 寫入文件並覆蓋舊文件

>> 加到文件的尾部,保留舊文件內容。

反短斜線 使用反短斜線能夠將一個命令的輸出做爲另一個命令的一個命令行參數。

命令: find . -mtime -1 -type f -print

用來查找過去24小時(-mtime –2則表示過去48小時)內修改過的文件。

若是您想將全部查找到的文件打一個包,則可使用如下腳本: 

#!/bin/sh # The ticks are backticks (`) not normal quotes ('): tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`

3) 流程控制

1.if

  "if" 表達式 若是條件爲真則執行then後面的部分:

if ....;then

....

elif

....;then

....

else

....

fi

大多數狀況下,可使用測試命令來對條件進行測試。好比能夠比較字符串、判斷文件是否存在及是否可讀等等„ 一般用" [ ] "來表示條件測試。注意這裏的空格很重要。要確保方括號的空格。

[ -f "somefile" ] :判斷是不是一個文件

[ -x "/bin/ls" ] :判斷/bin/ls是否存在並有可執行權限

[ -n "$var" ] :判斷$var變量是否有值

[ "$a" = "$b" ] :判斷$a和$b是否相等

執行man test能夠查看全部測試表達式能夠比較和判斷的類型。

直接執行如下腳本:

#!/bin/sh

if [ "$SHELL" = "/bin/bash" ]; then

echo "your login shell is the bash (bourne again shell)"

else

echo "your login shell is not bash but $SHELL"

fi

變量$SHELL包含了登陸shell的名稱,咱們和/bin/bash進行了比較。

快捷操做符 熟悉C語言的朋友可能會很喜歡下面的表達式:

[ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"

這裏 && 就是一個快捷操做符,若是左邊的表達式爲真則執行右邊的語句。 您也能夠認爲是邏輯運算中的與操做。

上例中表示若是/etc/shadow文件存在則打印」 This computer uses shadow passwors」。

一樣或操做(||)在shell編程中也是可用的。這裏有個例子:

#!/bin/sh

mailfolder=/var/spool/mail/james

[ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" exit 1; }

echo "$mailfolder has mail from:"

grep "^From " $mailfolder

該腳本首先判斷mailfolder是否可讀。若是可讀則打印該文件中的"From" 一行。若是不可讀則或操做生效,打印錯誤信息後腳本退出。

2.case 

case :

表達式能夠用來匹配一個給定的字符串,而不是數字。

case ... in 

...) do something here ; 

esac 

讓咱們看一個例子。

 file命令能夠辨別出一個給定文件的文件類型,好比:

 file lf.gz 

這將返回:

lf.gz: gzip compressed data, deflated, original filename, 

last modified: Mon Aug 27 23:09:18 2001, os: Unix 

咱們利用這一點寫了一個叫作smartzip的腳本,該腳本能夠自動解壓bzip2, gzip 和zip 類型的壓縮文件: 

#!/bin/sh 

ftype=`file "$1"` 

case "$ftype" in 

"$1: Zip archive"*) 

unzip "$1" ; 

"$1: gzip compressed"*) 

gunzip "$1" ; 

"$1: bzip2 

bunzip2 "$1" ; 

*) echo "File $1 can not be uncompressed with smartzip";; 

您可能注意到咱們在這裏使用了一個特殊的變量$1。

該變量包含了傳遞給該程序的第一個參數值。

也就是說,當咱們運行:

smartzip articles.zip 

$1 就是字符串 articles.zip 

3. selsect 

select 表達式是一種bash的擴展應用,尤爲擅長於交互式使用。用戶能夠從一組不一樣的值中進行選擇。

select var in ...  do 

break 

done 

.... now $var can be used .... 

下面是一個例子:

#!/bin/sh 

echo "What is your favourite OS?" 

select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do

break 
done 
echo "You have selected $var" 

下面是該腳本運行的結果:

What is your favourite OS? 

1) Linux 

2) Gnu Hurd 

3) Free BSD 

4) Other 

#? 1 

You have selected Linux

4.loop 

loop表達式:

while ...; do 

.... 

done 

while-loop 將運行直到表達式測試爲真。

關鍵字"break" 用來跳出循環。

而關鍵字」continue」用來不執行餘下的部分而直接跳到下一個循環。

for-loop

表達式查看一個字符串列表(字符串用空格分隔) 而後將其賦給一個變量:

for var in ....; do 

 .... 

done 

在下面的例子中,將分別打印

ABC到屏幕上:

 

#!/bin/sh 

for var in A B C  do 

 echo "var is $var" 

done 

5. 引號

在向程序傳遞任何參數以前,程序會擴展通配符和變量。這裏所謂擴展的意思是程序會把通配符(好比*)替換成合適的文件名,它變量替換成變量值。爲了防止程序做這種替換,您可使用引號

單引號和雙引號的區別

[root@linux ~]# name=TekTea
[root@linux ~]# echo $name
TekTea
[root@linux ~]# sayhello=」Hello $name」
[root@linux ~]# echo $sayhello
Hello TekTea
[root@linux ~]# sayhello='Hello $name'
[root@linux ~]# echo $sayhello
Hello $name

使用了單引號的時候,那 $name將失去原有的變量內容,僅爲通常字符的顯示型態而已!這裏必須要特別當心在乎!

因此,單引號與雙引號的最大不一樣在於雙引號仍然能夠保有變量的內容,但單引號內僅能是通常字符,而不會有特殊符號,咱們也能夠這裏理解:'$sayhello' 與 「\$sayhello」是相同的。

在Shell腳本開發過程當中,針對變量的單引號(‘)和雙引號(「)都是有應用場景的,根據個人經驗總結起來就是:

1. 獲取變量值的時候就使用雙引號(「),這是基本用法。

2. 若是是在腳本中要編寫一個新的腳本,同時這個新的腳本中還須要包含變量,你就能夠選擇使用單引號(‘)了,特別是生成一個臨時的expect腳本時,單引號(‘)就會常用到的。

6. Here documents 

當要將幾行文字傳遞給一個命令時,here documents(譯者注:目前尚未見到過對該詞適合的翻譯)一種不錯的方法。對每一個腳本寫一段幫助性的文字是頗有用的,此時若是咱們四有那個here documents就沒必要用echo函數一行行輸出。一個"Here document" 以<< 開頭,後面接上一個字符串,這個字符串還必須出如今here document的末尾。

下面是一個例子,在該例子中,咱們對多個文件進行重命名,而且使用here documents打印幫助:

#!/bin/sh 

# we have less than 3 arguments. Print the help text: 

if [ $# -lt 3 ]  then 

cat < 

ren -- renames a number of files using sed regular expressions 

USAGE: ren 'regexp' 'replacement' files...

EXAMPLE: rename all *.HTM files in *.html: 

ren 'HTM$' 'html' *.HTM 

HELP 

  exit 0 

fi 

 

OLD="$1" 

NEW="$2" 

# The shift command removes one argument from the list of 

# command line arguments. 

shift 

shift 

# $* contains now all the files: 

for file in $*; do 

if [ -f "$file" ]  then 

    newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` 

    if [ -f "$newfile" ]; then 

        echo "ERROR: $newfile exists already" 

    else 

    echo "renaming $file to $newfile ..."  

    mv "$file" "$newfile"

    fi 

fi 

done

   這是一個複雜一些的例子。讓咱們詳細討論一下。第一個if表達式判斷輸入命令行參數是否小於3個 (特殊變量$# 表示包含參數的個數) 。若是輸入參數小於3個,則將幫助文字傳遞給cat命令,而後由cat命令將其打印在屏幕上。打印幫助文字後程序退出。若是輸入參數等於或大於3個,咱們就將第一個參數賦值給變量OLD,第二個參數賦值給變量NEW。下一步,咱們使用shift命令將第一個和第二個參數從參數列表中刪除,這樣原來的第三個參數就成爲參數列表$*的第一個參數。而後咱們開始循環,命令行參數列表被一個接一個地被賦值給變量$file。接着咱們判斷該文件是否存在,若是存在則經過sed命令搜索和替換來產生新的文件名。而後將反短斜線內命令結果賦值給newfile。這樣咱們就達到了咱們的目的:獲得了舊文件名和新文件名。而後使用mv命令進行重命名。

4)函數

若是您寫了一些稍微複雜一些的程序,您就會發如今程序中可能在幾個地方使用了相同的代

碼,而且您也會發現,若是咱們使用了函數,會方便不少。一個函數是這個樣子的:

functionname() 

# inside the body $1 is the first argument given to the function 

# $2 the second ... 

body 

您須要在每一個程序的開始對函數進行聲明。

下面是一個叫作xtitlebar的腳本,使用這個腳本您能夠改變終端窗口的名稱。這裏使用了一個叫作help的函數。正如您能夠看到的那樣,這個定義的函數被使用了兩次

#!/bin/sh 

# vim: set sw=4 ts=4 et: 

help() 

  cat < 

xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole 

USAGE: xtitlebar [-h] "string_for_titelbar" 

OPTIONS: -h help text 

EXAMPLE: xtitlebar "cvs" 

HELP 

exit 0 

# in case of error or if -h is given we call the function help: 

[ -z "$1" ] && help 

[ "$1" = "-h" ] && help 

# send the escape sequence to change the xterm titelbar: 

echo -e "33]0;$107" 

#

在腳本中提供幫助是一種很好的編程習慣,這樣方便其餘用戶(和您)使用和理解腳本。 命令行參數    咱們已經見過$* 和 $1, $2 ... $9 等特殊變量,這些特殊變量包含了用戶從命令行輸入的參數。迄今爲止,咱們僅僅瞭解了一些簡單的命令行語法(好比一些強制性的參數和查看幫助的-h選項)。可是在編寫更復雜的程序時,您可能會發現您須要更多的自定義的選項。一般的慣例是在全部可選的參數以前加一個減號,後面再加上參數值 (好比文件名)。 有好多方法能夠實現對輸入參數的分析,可是下面的使用case表達式的例子無遺是一個不錯的方法。

#!/bin/sh 

help() 

  cat < 

This is a generic command line parser demo. 

USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2 

HELP 

exit 0 

while [ -n "$1" ]; do 

case $1 in 

  -h) help;shift 1;; # function help is called 

  -f) opt_f=1;shift 1;; # variable opt_f is set 

  -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2 

  --) shift;break;; # end of options 

  -*) echo "error: no such option $1. -h for help";exit 1;; 

*) break;; 

esac 

one 
echo "opt_f is $opt_f" echo "opt_l is $opt_l" echo "first arg is $1" echo "2nd arg is $2" 
  您能夠這樣運行該腳本: 
cmdparser -l hello -f -- -somefile1 somefile2  

 返回的結果是: 

opt_f is 1 

opt_l is hello 
first arg is -somefile1 

2nd arg is somefile2 

這個腳本是如何工做的呢?腳本首先在全部輸入命令行參數中進行循環,將輸入參數與case表達式進行比較,若是匹配則設置一個變量而且移除該參數。根據unix系統的慣例,首先輸入的應該是包含減號的參數.

 

附錄:

-e                          文件存在
-a                          文件存在(已被棄用)
-f                          被測文件是一個regular文件(正常文件,非目錄或設備)
-s                          文件長度不爲0
-d                          被測對象是目錄
-b                          被測對象是塊設備
-c                          被測對象是字符設備
-p                          被測對象是管道
-h                          被測文件是符號鏈接
-L                          被測文件是符號鏈接
-S(大寫)                    被測文件是一個socket
-t                          關聯到一個終端設備的文件描述符。用來檢測腳本的stdin[-t0]或[-t1]是一個終端
-r                          文件具備讀權限,針對運行腳本的用戶
-w                          文件具備寫權限,針對運行腳本的用戶
-x                          文件具備執行權限,針對運行腳本的用戶
-u                          set-user-id(suid)標誌到文件,即普通用戶可使用的root權限文件,經過chmod +s file實現
-k                          設置粘貼位
-O                          運行腳本的用戶是文件的全部者
-G                          文件的group-id和運行腳本的用戶相同
-N                          從文件最後被閱讀到如今,是否被修改

f1 -nt f2                   文件f1是否比f2新
f1 -ot f2                   文件f1是否比f2舊
f1 -ef f2                   文件f1和f2是否硬鏈接到同一個文件

二元比較操做符,比較變量或比較數字

整數比較:
-eq                      等於             if [ "$a" -eq "$b" ]
-ne                      不等於          if [ "$a" -ne "$b" ]
-gt                      大於             if [ "$a" -gt "$b" ]
-ge                      大於等於       if [ "$a" -ge "$b" ]
-lt                       小於             if [ "$a" -lt "$b" ]
-le                       小於等於       if [ "$a" -le "$b" ]

<                        小於(須要雙括號)        (( "$a" < "$b" ))
<=                      小於等於(...)                (( "$a" <= "$b" ))
>                        大於(...)                      (( "$a" > "$b" ))
>=                      大於等於(...)                (( "$a" >= "$b" ))

 

字符串比較:
=                         等於            if [ "$a" = "$b" ]
==                        與=等價
!=                        不等於         if [ "$a" = "$b" ]
<                         小於,在ASCII字母中的順序:
                          if [[ "$a" < "$b" ]]
                          if [ "$a" \< "$b" ]         #須要對<進行轉義
>                         大於

-z                        字符串爲null,即長度爲0
-n                        字符串不爲null,即長度不爲0

 

sed經常使用方法:(注意:sed 要處理的內容裏如有「*」或者換行等特殊字符,要在其前面加轉義字符「\」,如\n是換行)

1.置換某一行

[weishusheng@localhost fl-easycwmp]$ cat test.txt
arm
fl2440
ios
java
swif
[weishusheng@localhost fl-easycwmp]$ sed -i 's/fl2440/linux/' test.txt
[weishusheng@localhost fl-easycwmp]$ cat test.txt
arm
linux
ios
java
swif

-i 表示insert

-s:

s/regexp/replacement/表示嘗試匹配正則表達式模式空間。若是成功,regexp部分被替換爲replacement。替換換可能包含特殊字符和引用。

2.在某行連續添加多行內容

好比test.txt

[weishusheng@localhost fl-easycwmp]$ cat test.txt
arm
linux
ios
java
swif

[weishusheng@localhost fl-easycwmp]$ sed -i "1 a\hello world\nI am here\nI am going" test.txt
[weishusheng@localhost fl-easycwmp]$ cat test.txt
arm
hello world
I am here
I am going
linux
ios
java
swif

「」裏的1表示在行號爲1(從零開始)的地方插入。

a表示以煩斜槓爲開始符(插入內容不包括反斜槓)插入新行。

個人一個shell腳本的例程(功能:下載編譯VisualBoyAdvance)

#!/bin/bash  
#+--------------------------------------------------------------------------------------------
#|Description:  This shell script used to download VisualBoyAdvance and compile it, which is
#|              a game box can runs on FL2440.
#|     Author:  GuoWenxue <guowenxue@gmail.com>
#|  ChangeLog:
#|           1, Initialize 1.0.0 on 2015.04.23 by WeiShusheng
#|           2, Modify to static compile by guowenxue
#+--------------------------------------------------------------------------------------------

PRJ_PATH=`pwd`
PREFIX_PATH=$PRJ_PATH/install

PNG_NAME="libpng-1.4.3"
PNG_SUFIX="tar.bz2"
PNG_ADDR="http://down1.chinaunix.net/distfiles/libpng-1.4.3.tar.bz2"

SDL_NAME="SDL-1.2.13"
SDL_SUFIX="tar.gz"
SDL_ADDR="http://down1.chinaunix.net/distfiles/SDL-1.2.13.tar.gz"

VBOY_NAME="VisualBoyAdvance"
VBOY_SRC="-src-1.7.2"
VBOY_NOSRC="-1.7.2"
VBOY_SUFIX="tar.gz"
VBOY_ADDR="http://downloads.sourceforge.net/project/vba/VisualBoyAdvance/1.7.2/VisualBoyAdvance-src-1.7.2.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fvba%2Ffiles%2FVisualBoyAdvance%2F1.7.2%2F&ts=1429342329&use_mirror=ncu
"

if [ ! -d $PREFIX_PATH ] ; then
    mkdir -p $PREFIX_PATH
fi

CROSS=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-
export CC=${CROSS}gcc
export CXX=${CROSS}g++
export CPP=${CROSS}cpp
export AS=${CROSS}as
export LD=${CROSS}ld
export AR=${CROSS}ar
export RANLIB=${CROSS}ranlib
export STRIP=${CROSS}strip

cd ${PRJ_PATH}/
if [ ! -f $PREFIX_PATH/lib/libpng.a ] ; then 
    # Download libpng source code packet 
    if [ ! -s $PNG_NAME.$PNG_SUFIX ] ; then 
        echo "+------------------------------------------------------------------+" 
        echo "|  Download $PNG_NAME.$PNG_SUFIX now "  
        echo "+------------------------------------------------------------------+" 
        wget $PNG_ADDR 
    fi 

    #unzip libpng
    if [ ! -d $PNG_NAME ];then 
        tar -xjf $PNG_NAME.$PNG_SUFIX 

        if [ $? != 0 ] ; then
            echo "Decompress $PNG_NAME.$PNG_SUFIX failure and exit now..."
            exit 1;
        else 
            echo "Decompress $PNG_NAME.$PNG_SUFIX and compile it..."
        fi
    fi

    cd ${PRJ_PATH}/$PNG_NAME
    ./configure  --host=arm-linux --prefix=$PREFIX_PATH --enable-static --disable-shared
    make && make install
    if [ $? != 0 ] ; then
        echo "Compress $PNG_NAME failure, exit now..."
        exit 1;
    fi
fi

cd ${PRJ_PATH}/
if [ ! -f $PREFIX_PATH/lib/libSDL.a ] ; then 
    # Download SDL source code packet 
    if [ ! -s $SDL_NAME.$SDL_SUFIX ] ; then 
        cd ${PRJ_PATH}/
        echo "+------------------------------------------------------------------+" 
        echo "|  Download $SDL_NAME.$SDL_SUFIX now "  
        echo "+------------------------------------------------------------------+" 
        wget $SDL_ADDR 
    fi 


    #unzip SDL 
    if [ ! -d $SDL_NAME ];then 
        tar -xzf $SDL_NAME.$SDL_SUFIX 

        if [ $? != 0 ] ; then
            echo "Decompress $SDL_NAME.$SDL_SUFIX failure and exit now..."
            exit 1; 
        else
            echo "Decompress $SDL_NAME.$SDL_SUFIX and compile it..."
        fi
    fi 

    cd ${PRJ_PATH}/$SDL_NAME 
    ./configure  --host=arm-linux --prefix=$PREFIX_PATH --enable-static --disable-shared
    make && make install

    if [ $? != 0 ] ; then
        echo "Compress $SDL_NAME failure, exit now..."
        exit 1;
    fi
fi


cd ${PRJ_PATH}/
if [ ! -f VisualBoyAdvance ] ; then 
    # Download VBOY source code packet 
    if [ ! -s $VBOY_NAME$VBOY_SRC.$VBOY_SUFIX ] ; then 
        echo "+------------------------------------------------------------------+" 
        echo "|  Download $VBOY_NAME$VBOY_SRC.$VBOY_SUFIX now " 
        echo "+------------------------------------------------------------------+" 
        wget $VBOY_ADDR 
    fi 

    #unzip VBOY 
    if [ ! -d $VBOY_NAME$VBOY_NOSRC ];then 
        tar -xzf $VBOY_NAME$VBOY_SRC.$VBOY_SUFIX 

        if [ $? != 0 ] ; then
            echo "Decompress $VBOY_NAME$VBOY_SRC.$VBOY_SUFIX failure and exit now..."
            exit 1; 
        else
            echo "Decompress $VBOY_NAME$VBOY_SRC.$VBOY_SUFIX and compile it..."
        fi
    fi 
    
    cd ${PRJ_PATH}/$VBOY_NAME$VBOY_NOSRC 
    sed -i 's/utilGzWriteFunc = (int (\*)(void \*,void \* const, unsigned int))gzwrite;/utilGzWriteFunc = (int (\*)(gzFile_s\*,void \* const, unsigned int))gzwrite;/' src/Util.cpp 

    export CFLAGS+="-I$PREFIX_PATH/include -I$PREFIX_PATH/include/SDL"
    export CXXFLAGS+="-I$PREFIX_PATH/include -I$PREFIX_PATH/include/SDL"
    export LDFLAGS="-L$PREFIX_PATH/lib" 
    export SDL_CONFIG=$PREFIX_PATH/bin
    export LIBS+=-lSDL
    if [ -f Makefile ] ; then 
        make distclean 
    fi
    ./configure --host=arm-linux --prefix=$PREFIX_PATH --with-sdl-exec-prefix=$PREFIX_PATH --with-sdl-exec-prefix=$PREFIX_PATH
    make && make install
    ${STRIP} $PREFIX_PATH/bin/VisualBoyAdvance
fi
相關文章
相關標籤/搜索