linux程式設計——shell程式設計(第二章)

來源:互聯網
上載者:User

標籤:

這篇是shell的命令與命令的執行,文章中的命令在這裡下載命令命令的執行,上一篇是shell中的變數,條件判斷,控制結構和函數,上上篇介紹了什麼是shell,管道和重新導向,作為程式設計語言的shell。
2.6.5    命令在shell指令碼程式內部可以執行兩類命令。一類是可以在命令提示字元中執行的"普通"命令,也成為外部命令,一類是"內建"命令,也成為內部命令。內建命令是在shell內部實現的,它們不能作為外部程式被調用。然後,大多數的內部命令同時也提供了獨立啟動並執行程式版本,這是POSIX規範的一部分。
1.break命令在控制條件未滿足之前,跳出for,while或者until迴圈。預設情況下,break只跳出一層迴圈。
2.:命令冒號:命令是一個空命令,它偶爾會被用於簡化條件邏輯,相當於true的一個別名。由於它是內建命令,所以啟動並執行比true快,但它的輸出可讀性較差。例如可以使用while :實現一個無限迴圈,代替更常見的while true。
3.continue命令這個命令使for、while或until迴圈跳到下一次迴圈繼續執行,迴圈變數取迴圈列表中的下一個值。
4..命令點 .命令用於當前shell中執行命令
../shell_script
通常,當一個指令碼執行一條外部命令或指令碼程式時,它會建立一個新的環境(一個子shell),命令將在這個新環境中執行,在命令執行完畢後,這個環境將被丟棄,留下退出碼返回給父shell。但外部的source命令和點命令(這兩個命令是同義字)在執行指令碼程式中列出的命令時,使用的是調用該指令碼程式的同一個shell。
因為在預設情況下,shell指令碼程式會在一個新建立的環境中執行,所以指令碼程式對環境變數所作的任何修改都會丟失。而點命令允許執行的指令碼程式改變當前環境。如果要把一個指令碼當做“包裹器”來為後續執行的一些其他命令設定環境時,這個命令通常就很有用。
在shell指令碼程式中,點命令的作用有點類似與C或者C++中的#include指令,它在當前上下文中執行命令,可以使用它將變數和函數定義結合進指令碼程式。
5.echo命令雖然,X/Open建議在現在shell中使用printf命令,但是還是經常使用echo命令來輸出結尾帶有分行符號的字串。
一個常見的問題是如何 去掉分行符號,linux常用的解決方式為: echo -n "string to output"
6.eval命令 eval命令允許對參數進行求值,它是shell的內建命令,通常不會以單獨命令的形式存在。
foo=10
x=foo
y=‘$‘$x
echo $y
foo=10
x=foo
eval y=‘$‘$x
echo $y
前一個結果輸出$foo,後一個結果輸出10。 eval命令有點像額外的$,它給出一個變數的值的值
有點類似指標? $類似於*,取出地址所指向的內容。
7.exec命令exec命令有兩種不同的用法,它的典型用法是將當前shell替換為一個不同的程式。例如:
exec wall "Thanks for all the fish"
指令碼中的這個命令會用wall命令替換當前的shell,指令碼程式中exec命令後面的代碼都不會執行,因為執行這個指令碼的shell已經不存在了。
8.exit n命令exit命令使指令碼程式以退出碼n結束運行。如果在任何一個互動式shell的命令提示字元中使用這個命令,它會使退出系統。如果允許指令碼程式退出時不指定一個退出狀態,那麼該指令碼中最後一條被執行命令的狀態將被用作返回值。在指令碼程式中提供一個退出碼總是一個良好的習慣。
在shell指令碼編程中,退出碼0表示成功。
下面是一個簡單的例子,如果目前的目錄下存在一個名為.profile的檔案,它返回0表示成功,返回1表示失敗:
#!/bin/sh
if [ -f *.profile ]
then
    exit 0
fi
exit 1
如果追求更簡潔的版本,則為:
[ -f *.profile ] && exit 0 || exit 1
9.export命令 export命令將作為它參數的變數匯出到子shell中,並使之在子shell中有效。在 預設情況下,在一個 shell中被建立的變數在這個shell調用的下級shell中是不可用的。export命令把自己的參數建立為一個環境變數,而這個環境變數可以被當前程式調用的其他指令碼和程式看見。從更技術的角度來說, 被匯出的變數構成從該shell衍生的任何子進程的環境變數。
一旦一個變數被shell匯出,它就可以被該shell調用的任何指令碼使用,也可以被後續依次調用的任何shell使用。
10.expr命令expr命令將它的參數當作一個運算式來求值。它最常見的用法就是進行簡單數學運算:
x=`expr $x + 1`(注意,這個命令貌似不能得到相應的結果,使用$()可以達到目的,後來發現反引號是Tab上面的鍵,不是單引號)
反引號`‘字元使x取值為命令expr $x + 1的執行結果。也可以使用文法$()替換反引號‘‘,如下所示:
x=$(expr $x + 1)
運算式求值                    說明
expr1 | expr2                如果expr1非零,則等於expr1,否則等於expr2
expr1 & expr2                只要有一個運算式為零,則等於零,否則等於expr1
在較新的指令碼程式中,expr命令通常被替換為 更有效$((...))文法
11.printf命令只有新版本的shell才提供printf命令,X/Open規範建議我們應該用它來代替echo命令,以產生格式化的輸出。
printf "%s\n" hello
printf "%s %d\t%s" "hi There" 15 people
12.return命令return命令的作用是使函數返回。return命令有一個數值參數,這個參數在調用該函數的指令碼程式裡被看做是該函數的返回值。如果沒有指定參數,return命令預設返回最後一條命令的退出碼。
13.set命令set命令的作用是為shell設定參數變數。許多命令的輸出結果是以空格分隔的值,如果需要使用輸出結果中的某個域,這個命令就非常有用。
假設想在一個shell指令碼中使用當前月份的名字。系統本身提供了一個date命令,它的輸出結果中包含了字串形式的月份名稱,但是需要把它與其他地區分隔開。可以將set命令和$(...)結構相結合起來執行date命令,並且返回想要的結果。date命令的輸出把月份字串作為它的第二個參數:
#!/bin/sh
echo the date is $(date)
set $(date)
echo the month is $2
exit 0
這個程式把date命令的輸出設定為參數列表,然後通過位置參數$2獲得月份。
通過這個例子可以看到date命令怎樣提取位置參數,由於date命令的輸出受本地語言的影響較大,應該使用date +%B命令來提取月份名字。
可以通過set命令和它的參數來控制shell的執行方式,其中最常用的命令格式是set -x,它讓一個指令碼程式跟蹤現實它當前執行的命令。
14.shift命令shift命令把所有參數變數左移一個位置,使$2變成$1,$3變成$2,以此類推。原來$1的值將被丟棄,而$0保持不變。如果調用shift命令時指定了一個數值參數,則表示所有的參數將左移指定的次數。$*,[email protected]和$#等其他變數也將根據參數變數的安排而作相應的變動。
15.trap命令trap命令用於指定在接受到訊號後將要採取的行動,trap命令的一種常見的使用者是在指令碼程式被中斷時完成清理工作。曆史上,shell總是用數字來代表訊號,但新的指令碼程式應該使用訊號的名字,它們定義在標頭檔signal.h中,使用訊號名時需要省略SIG首碼。可以在命令提示字元下輸入命令trap -l來查看訊號編號及其關聯的名稱。
trap命令有兩個參數,第一個參數是接收到指定訊號時將要採取的行動,第二個參數是要處理的訊號名。
trap command signal
指令碼程式通常是從上到下的順序解釋執行的,因此必須在要保護的那部分代碼之前指定trap命令。
訊號是指那些被非同步發送到一個程式的事件,在預設情況下,它們通常會終止一個程式的運行。
如果要重設某個訊號的處理方式到其預設值,只需要將command設定為-。如果要忽略某個訊號,就把command設定為空白字串‘‘。一個不帶參數的trap命令將列出當前設定的訊號以及其行動的清單。
訊號                說明
HUP(1)            掛起,通常因終端掉線或使用者退出而引發
INT(2)            中斷,通常因按下Ctrl+C按鍵組合而引發
QUIT(3)            退出,通常因按下Ctrl+\組合健而引發
ABRT(6)            終止,通常因某些嚴重的執行錯誤而引發
ALRM(14)        警示,通常用來處理逾時
TERM(15)        中之,通常在系統關機時發送
16.unset命令unset命令的作用是從環境中刪除變數或函數,這個命令不能刪除shell本身定義的唯讀變數(如IFS)
17.另外兩個有用的命令和Regex這兩個命令雖然不是shell的一部分,但是在shell程式時經常用到。同時介紹Regex,一種出現在所有linux以及與之相關聯程式中的模式比對特徵。
find命令
find命令用於搜尋檔案。
find / -name test -print
這個命令從根目錄開始尋找檔案名稱為test的檔案,並且輸出該檔案的完整路徑。
然後,這個命令的執行需要花費很長時間,並且網路上的Windows機器的硬碟也會高速轉動。這是因為linux機器掛載了一大塊Windows機器的檔案系統,看起來似乎是Windows檔案系統也被搜尋了,儘管我們知道要尋找的檔案應該在Linux機器上。
這就是第一個選項發揮作用的時候了,如果指定-mount選項,就可以告訴find命令不要搜尋掛載的其他檔案系統目錄。這樣搜尋速度會更快。
find命令的完整文法格式如下所示:
find [path] [options] [tests] [actions]
path部分:既可以使用絕對路徑,如/bin,也可以使用相對路徑,如.。如果需要,也可以指定多個路徑,如find /var /home。
find命令有許多選項可用,如:
選項                        含義
-depth                    在查看目錄本身之前先搜尋目錄的內容
-follow                    跟隨符號連結
-maxdepths N            最多搜尋N層目錄
-mount(或-xdev)            不搜尋其他檔案系統中的目錄
測試                        含義
-type c                    檔案的類型為c,最常見的是d(目錄)和f(普通檔案)
操作符                    含義
!                        -not測試取反
-a                        -and兩個測試都必須為真
-o                        -or兩個測試有一個必須為真
在目前的目錄下搜尋比檔案test28更晚的檔案:
$ find . -newer test28 -print
可以發現結果中還包含了目前的目錄,如果只想要普通檔案,則增加一個額外的測試-type f
$ find . -newer test28 -type f -print
可以組合條件搜尋,尋找目前的目錄包含_的檔案或者比test28更晚的檔案
$ find . \( -newer test28 -o -name "*_*" \) -type f -print
由於圓括弧對shell有特殊的含義,因此必須使用反斜線來引用圓括弧。
grep命令
這個名字代表的是通用Regex解析器(General Regular Expresssion Parser,簡寫為grep),使用grep命令在檔案中搜尋字串。一種常見的用法是在使用find命令時,將grep作為傳遞給-exec的一條命令。
grep命令使用一個選項,一個要匹配的模式和要搜尋的檔案,它的文法如下所示:
grep [options] pattern [files]
如果沒有提供檔案名稱,則grep命令將搜尋標準輸入。
選項                含義
-c                輸出匹配行的數目,而不是輸出匹配的行
-E                啟用擴充運算式
-h                取消每個輸出行的普通首碼,即匹配查詢模式的檔案名稱
-i                忽略大小寫
-l                只列出包含匹配行的檔案名稱,而不輸出真正的匹配行
-v                對匹配模式取反,即搜尋不匹配行而不是匹配行
例如:
$ grep in test1
顯示test1中包含in的行

$ grep -c in test1 test2 test3
顯示test1,test2,test3中包含in的行數
$ grep -c -v in test1 test2
顯示test1,test2中不包含in的行數
Regex
Regex中最常用的特殊字元如下所示:
字元            含義
^            指向一行的開頭
$            指向一行的結尾
.            任意單個字元
[]            方括弧內包含一個字元範圍,其中任何一個字元都可以被匹配,例如a~e,或
            在字元範圍前面加上^表示使用反向字元範圍。

在方括弧中還可以使用一些有用的特殊匹配模式,如下所示:
匹配模式                    含義
[:alnum:]                字母與數字字元
[:alpha:]                字母
[:ascii:]                ASCII字元
[:blank:]                空格或者定位字元
[:cntrl:]                ASCII控制字元
[:digit:]                數字
[:graph:]                非控制,非空格字元
[:lower:]                小寫字母
[:print:]                可列印字元
[:punct:]                標點符號字元
[:space:]                空白字元
[:upper:]                大寫字母
[:xdigit:]                十六進位數字
例如:
$ grep e$ test1

尋找test1中以e為結尾的行
$ grep ^e test1 test2
尋找顯示test1,test2中以e為開頭的行
$ grep a[[:blank:]] test1 test2

顯示test1,test2中以e為結尾的單詞
$ grep th.[[:space:]] test1 test2 test3
顯示test1,test2,test3中以th開頭的3個字母組成的單詞,用字元.來匹配一個額外的字元
$ grep -E [a-z]\{10\} test1 test2 test3
尋找顯示test1,test2,test3中只有10個字元長的全部由小寫字母組成的單詞。
2.6.6 命令的執行編寫指令碼程式時,需要 捕獲一條命令的執行結果,並把它用在shell指令碼程式中。即 執行一條命令,並把命令的輸出放到一個變數中
所有的新指令碼程式都應該 使用$(...)形式$(command)的結果就是其中命令的輸出。注意,這不是該命令的退出狀態,而是它的字串形式的輸出結果。例如:
echo The current directory is $PWD
echo The current users are $(who)
如果要將命令的結果放到一個變數中,可以按照通常的方法來給它賦值,如下所示:
value=$(who)
echo $value
這種把命令的執行結果放到變數中的能力是非常強大的,它使得在指令碼程式中使用現有命令並捕獲其輸出變得很容易。如果需要把一條命令在標準輸出上的輸出轉換為一組參數,並且將它們用做為另一個程式的參數,命令xargs可以完成這個任務。
1.算數擴充之前介紹expr命令可以處理一些簡單的算數命令,但是這個命令執行起來相當慢,因為它需要調用一個新的shell來處理expr命令。
一個更新更好的辦法是 使用$((...))擴充。把準備求值的運算式括在$((...))中能夠更有效地完成簡單的算數運算。如下所示:
x=0
while [ "$x" -ne 10 ]
do
    echo $x
    x=$(($x+1))
done
注意,這與x=$(...)命令不同,兩對圓括弧用於算數替換,而我們之前見到的一對圓括弧用於 命令的執行和擷取輸出。
???疑惑的是把x當做字串處理判斷條件,也得到相同的輸出( "$x" != 10 )
2.參數擴充之前介紹過簡單的參數賦值和擴充了,如下所示:
foo=fred
echo $foo
???疑惑 shell中的賦值,有點指標傳遞的感覺,foo變數中儲存fred的指標,取地址運算子*類似與$,獲得變數的內容
如果想編寫一個指令碼程式,來處理test1和test2兩個檔案,可能這樣寫:
for i in 1 2
do
    ./testi
done
在每次迴圈中,發現./testi not found
問題在於./testi變數無法被替換,為了保護變數名中類似於$i部分的擴充,需要 把i放在花括弧中,如下所示
.test${i}
這樣,每次迴圈中,變數i的值替換為$(i),給出正確的檔案名稱,把參數的值替換進了一個字串。
可以在shell中採用多種參數替換方法,對於多參數處理問題來說,這些方法通常提供了一種精巧的解決方案。
參數擴充            說明
${param:-default}    如果param為空白,就把它設定為default的值
#{#param}            給出param的長度
${param%word}        從param的尾部開始刪除與word匹配的最小部分,然後返回剩餘部分
${param%%word}        從param的尾部開始刪除與word匹配的最長部分,然後返回剩餘部分
${param#word}        從param的頭部開始刪除與word匹配的最小部分,然後返回剩餘部分
${param##word}        從param的頭部開始刪除與word匹配的最長部分,然後返回剩餘部分
當處理字串時,這些替換通常是非常有用的,特別是對字串進行部分刪除的最後4個參數擴張方法,在處理檔案名稱和路徑時非常有用。

linux程式設計——shell程式設計(第二章)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.