SHELL編程基本知識點一

SHELL編程基本知識點一

1,起始點

在每個腳本的開頭都使用"#!",這意味着告訴你的系統這個文件的執行需要指定一個解

釋器.#!實際上是一個 2 字節[1]的魔法數字,這是指定一個文件類型的特殊標記, 換句話說, 在

這種情況下,指的就是一個可執行的腳本.在#!之後接着是一個路徑名.這個路徑名指定了一個解釋腳本中命令的程序,這個程序可以是 shell,程序語言或者是任意一個通用程序.這個指定的程序從頭開始解釋並且執行腳本中的命令(從#!行下邊的一行開始),忽略註釋.

如:

#!/bin/sh

#!/bin/bash

#!/usr/bin/perl

#!/usr/bin/tcl

#!/bin/sed -f

#!/usr/awk -f

2,條件表達式

條件表達式用於 [[ 複合命令以及內建命令 test 和 [ 中,用來測試文件屬性,進行字符串和算術比較。表達式使用下面的單目或二進制操作構造. 如果某操作的任何 file 參數的形式是 /dev/fd/n,那麼將檢查文件描述符n。如果某操作的file參數是 /dev/stdin, /dev/stdout 或者 /dev/stderr 之一,將分別檢查文件描述符 0,1 和 2。

[ -a FILE ]

如果 FILE 存在則爲真.

[ -b FILE ]

如果 FILE 存在且是一個塊特殊文件則爲真.

[ -c FILE ]

如果 FILE 存在且是一個字特殊文件則爲真.

[ -d FILE ]

如果 FILE 存在且是一個目錄則爲真.

[ -e FILE ]

如果 FILE 存在則爲真.

[ -f FILE ]

如果 FILE 存在且是一個普通文件則爲真.

[ -g FILE ]

如果 FILE 存在且已經設置了SGID則爲真.

[ -h FILE ]

如果 FILE 存在且是一個符號連接則爲真.

[ -k FILE ]

如果 FILE 存在且已經設置了粘制位則爲真.

[ -p FILE ]

如果 FILE 存在且是一個名字管道(F如果O)則爲真.

[ -r FILE ]

如果 FILE 存在且是可讀的則爲真.

[ -s FILE ]

如果 FILE 存在且大小不爲0則爲真.

[ -t FD ]

如果文件描述符 FD 打開且指向一個終端則爲真.

[ -u FILE ]

如果 FILE 存在且設置了SUID (set user ID)則爲真.

[ -w FILE ]

如果 FILE 如果 FILE 存在且是可寫的則爲.

[ -x FILE ]

如果 FILE 存在且是可執行的則爲真.

[ -O FILE ]

如果 FILE 存在且屬有效用戶ID則爲真.

[ -G FILE ]

如果 FILE 存在且屬有效用戶組則爲真.

[ -L FILE ]

如果 FILE 存在且是一個符號連接則爲真.

[ -N FILE ]

如果 FILE 存在 and has been mod如果ied since it was last read則爲真.

[ -S FILE ]

如果 FILE 存在且是一個套接字則爲真.

[ FILE1 -nt FILE2 ]

如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1 exists and FILE2 does not則爲真.

[ FILE1 -ot FILE2 ]

如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在則爲真.

[ FILE1 -ef FILE2 ]

如果 FILE1 和 FILE2 指向相同的設備和節點號則爲真.

[ -o OPTIONNAME ]

如果 shell選項 “OPTIONNAME” 開啓則爲真.

[ -z STRING ]

“STRING” 的長度爲零則爲真.

[ -n STRING ] or [ STRING ]

“STRING” 的長度爲非零 non-zero則爲真.

[ STRING1 == STRING2 ]

如果2個字符串相同. “=” may be used instead of “==” for strict POSIX compliance則爲真.

[ STRING1 != STRING2 ]

如果字符串不相等則爲真.

[ STRING1 < STRING2 ]

如果 “STRING1” sorts before “STRING2” lexicographically in the current locale則爲真.

[ STRING1 > STRING2 ]

如果 “STRING1” sorts after “STRING2” lexicographically in the current locale則爲真.

[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.

3,特殊字符

#

註釋,行首以#開頭爲註釋(#!是個例外). 註釋也可以在本行空白的後邊.

;

命令分隔符,可以用來在一行中來寫多個命令.

;;

終止"case"選項.

.

.命令等價於 source 命令(見 Example 11-20).這是一個 bash 的內建命令.

.作爲文件名的一部分.如果作爲文件名的前綴的話,那麼這個文件將成爲隱藏文件.

.命令如果作爲目錄名的一部分的話,那麼.表達的是當前目錄.".."表示上一級目錄.

.字符匹配,這是作爲正則表達是的一部分,用來匹配任何的單個字符.

"

部分引用" " 可引用除$、` 、\ 、外的任意字符或字符串," "中的變量能夠正常顯示變量值.

'

全引用' '與" "類似,不同在於shell會忽略任何的引用值.

, 逗號鏈接了一系列的算術操作,雖然裏邊所有的內容都被運行了,但只有最後一項被

返回.

如:let "t2 = ((a = 9, 15 / 3))"

# Set "a = 9" and "t2 = 15 / 3"

\ 轉義字符,如\X 等價於"X"或'X'.

/ 文件名路徑分隔符.或用來做除法操作.

` 後置引用,命令替換.

:

空命令,等價於"NOP"(no op,一個什麼也不幹的命令).也可以被認爲與 shell 的內建命令

(true)作用相同.":"命令是一個 bash 的內建命令,它的返回值爲 0,就是 shell 返回的 true.

如:

:

echo $?

# 0

死循環 如:

while :

do

operation-1

operation-2

...

operation-n

done

# 與下邊相同:

while true

do

...

done

在 if/then 中的佔位符,如:

if condition

then : # 什麼都不做,引出分支.

else

take-some-action

fi

在一個 2 元命令中提供一個佔位符,具體見 Example 8-2,和"默認參數".如:

: ${username=`whoami`}

# ${username=`whoami`}

如果沒有":"的話,將給出一個錯誤,除非"username"是個命令

使用"參數替換"來評估字符串變量.如:

: ${HOSTNAME?} ${USER?} ${MAIL?}

如果一個或多個必要的環境變量沒被設置的話, 就打印錯誤信息.

"變量擴展/子串替換"

在和 > (重定向操作符)結合使用時,把一個文件截斷到 0 長度,沒有修改它的權限.

如果文件在之前並不存在,那麼就創建它.如:

: > data.xxx

#文件"data.xxx"現在被清空了.

#與 cat /dev/null >data.xxx 的作用相同.然而,這不會產生一個新的進程,因爲":"是一個內建命令.

在和>>重定向操作符結合使用時,將不會對想要附加的文件產生任何影響.

如果文件不存在,將創建.

注意: 這隻適用於正規文件,而不是管道,符號連接,和某些特殊文件.

!

取反操作符,將反轉"退出狀態"結果.也會反轉 test 操作符的意義.比

如修改=爲!=.!操作是 Bash 的一個關鍵字.

在一個不同的上下文中,!也會出現在"間接變量引用".

在另一種上下文中,!還能反轉 bash 的"history mechanism"

需要注意的是,在一個腳本中,"history mechanism"是被禁用的.

*

萬能匹配字符,用於文件名匹配(這個東西有個專有名詞叫 file globbing),或者是正則

表達式中.注意:在正則表達式匹配中的作用和在文件名匹配中的作用是不同的.

*

數學乘法.

**是冪運算.

?

測試操作.在一個確定的表達式中,用?來測試結果.

(())結構可以用來做數學計算或者是寫 c 代碼,那?就是 c 語言的 3 元操作符的

一個.

在"參數替換"中,?測試一個變量是否被 set 了.

?在 file globbing 中和在正則表達式中一樣匹配任意的單個字符.

$

變量替換;在正則表達式中作爲行結束符.

${}

參數替換

$*,$@

位置參數

$?

退出狀態變量.$?保存一個命令/一個函數或者腳本本身的退出狀態.

$$

進程 ID 變量.這個$$變量保存運行腳本進程 ID

()

命令組.如:

(a=hello;echo $a)

注意:在()中的命令列表,將作爲一個子 shell 來運行.在()中的變量,由於是在子shell 中,所以對於腳本剩下的部分是不可用的.

用在數組初始化,如:

Array=(element1,element2,element3)

{xxx,yyy,zzz...}

大括號擴展,如:

cat {file1,file2,file3} > combined_file

# 把 file1,file2,file3 連接在一起,並且重定向到 combined_file 中.

cp file22.{txt,backup}

# 拷貝"file22.txt" 到"file22.backup"中

一個命令可能會對大括號中的以逗號分割的文件列表起作用[1]. file globbing 將對

大括號中的文件名作擴展.

注意: 在大括號中,不允許有空白,除非這個空白是有意義的.

echo {file1,file2}\ :{\ A," B",' C'}

file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C

{}

代碼塊.又被稱爲內部組.事實上,這個結構創建了一個匿名的函數.但是與函數不同的

是,在其中聲明的變量,對於腳本其他部分的代碼來說還是可見的.

注意: 與()中的命令不同的是,{}中的代碼塊將不能正常地開啓一個新 shell.

{} \; 路徑名.一般都在 find 命令中使用.這不是一個 shell 內建命令.

注意: ";"用來結束 find 命令序列的-exec 選項.

[] test.

test 的表達式將在[]中.

值得注意的是[是 shell 內建 test 命令的一部分,並不是/usr/bin/test 中的擴展命令的一個連接.

[[]] test.

test 表達式放在[[]]中.(shell 關鍵字)

具體查看[[]]結構的討論.

[ ]

數組元素

Array[1]=slot_1

echo ${Array[1]}

[ ]

字符範圍

在正則表達式中使用,作爲字符匹配的一個範圍

(()) 數學計算的擴展

在(())結構中可以使用一些數字計算.

具體參閱((...))結構.

>&>>&>><

重定向.

scriptname >filename 重定向腳本的輸出到文件中.覆蓋文件原有內容.

command &>filename 重定向 stdout 和 stderr 到文件中

command >&2 重定向 command 的 stdout 到 stderr

scriptname >>filename 重定向腳本的輸出到文件中.添加到文件尾端,如果沒有文件,則創建這個文件.

<<

重定向,用在"here document"

<<<

重定向,用在"here string"

<,>

ASCII 比較

\<,\>

正則表達式中的單詞邊界.如:

bash$grep '\<the\>' textfile

|

管道.分析前邊命令的輸出,並將輸出作爲後邊命令的輸入.這是一種產生命令鏈的好方法.

>|

強制重定向(即使設置了 noclobber 選項--就是-C 選項).這將強制的覆蓋一個現存文件.

||

或-邏輯操作.

&

後臺運行命令.一個命令後邊跟一個&,將表示在後臺運行.

&& 與-邏輯操作.

-

用於重定向 stdin 或 stdout.

cd source/directory

tar cf - . | (cd ../dest/directory; tar xpvf -)

- 之前工作的目錄."cd -"將回到之前的工作目錄,具體請參考"$OLDPWD"環境變量.

注意:一定要和之前討論的重定向功能分開,但是隻能依賴上下文區分.

-

算術減號.

=

算術等號,有時也用來比較字符串.

+

算術加號,也用在正則表達式中.

+

選項,對於特定的命令來說使用"+"來打開特定的選項,用"-"來關閉特定的選項.

%

算術取模運算.也用在正則表達式中.

~

home 目錄.

~+

當前工作目錄,相當於$PWD 變量.

~-

之前的工作目錄,相當於$OLDPWD 內部變量.

=~

用於正則表達式,這個操作將在正則表達式匹配部分講解,只有 version3 才支持.

^

行首,正則表達式中表示行首."^"定位到行首.

4,控制字符

修改終端或文本顯示的行爲.控制字符以 CONTROL + key 組合.

控制字符在腳本中不能正常使用.

Ctl-B

光標後退,這應該依賴於 bash 輸入的風格,默認是 emacs 風格的.

Ctl-C

Break,終止前臺工作.

Ctl-D

從當前 shell 登出(和 exit 很像)

"EOF"(文件結束符).這也能從 stdin 中終止輸入.

在 console 或者在 xterm window 中輸入的時候,Ctl-D 將刪除光標下字符.

當沒有字符時,Ctrl-D 將退出當前會話.在 xterm window 也有關閉窗口

的效果.

Ctl-G

beep.在一些老的終端,將響鈴.

Ctl-H

backspace,刪除光標前邊的字符.

Ctl-I

就是 tab 鍵.

Ctl-J

新行.

Ctl-K

垂直 tab.(垂直 tab?新穎,沒聽過)作用就是刪除光標到行尾的字符.

Ctl-L

clear,清屏.

Ctl-M

回車

Ctl-Q

繼續(等價於 XON 字符),這個繼續的標準輸入在一個終端裏

Ctl-S

掛起(等價於 XOFF 字符),這個被掛起的 stdin 在一個終端裏,用 Ctl-Q 恢復

Ctl-U

刪除光標到行首的所有字符,在某些設置下,刪除全行.

Ctl-V

當輸入字符時,Ctl-V 允許插入控制字符.比如,下邊 2 個例子是等價的

Ctl-W

刪除當前光標到前邊的最近一個空格之間的字符.

在某些設置下,刪除到第一個非字母或數字的字符.

Ctl-V 在文本編輯器中十分有用,在 vim 中一樣.

echo -e '\x0a'

echo <Ctl-V><Ctl-J>

Ctl-Z

終止前臺工作.

5,命令行處理

命令行處理解釋了Shell如何處理一個命令的內部機制

Shell從標準輸入或腳本讀取的每一行稱爲管道(pipeline),每一行包含一個或多個命令,這些命令用管道符隔開,Shell對每一個讀取的管道都按照下面的步驟處理:

1、將命令分割成令牌(token),令牌之間以元字符分隔,Shell的元字符集合是固定不變的,包括空格、Tab鍵、換行字符、分號(;)、小括號、輸入重定向符(<)、輸出重定向符(>)、管道符(|)和&符號,令牌可以是單詞(word)、關鍵字,也可以是I/O重定向器和分號。

2、檢查命令行的第一個令牌是否爲不帶引號或反斜槓的關鍵字,如果此令牌是開放關鍵字,開放關鍵字指if、while、for或其他控制結構中的開始符號,Shell就認爲此命令是複合命令,併爲該複合命令進行內部設置,讀取下一條命令,再次啓動進程。如果此令牌不是複合命令的開始符號,如該令牌是then、else、do、fi、done等符號,這說明該令牌不應該處在命令行的首位,因此,Shell提示語法錯誤信息。

3、檢查命令行的第一個令牌是否爲某命令的別名,這需要將此令牌與別名(alia)列表逐個比較,如果匹配,說明該令牌是別名,則將該令牌替換掉,返回步驟1,否則進入步驟4。這種機制允許別名遞歸,也允許定義關鍵字別名,比如可以用下面命令定義while關鍵字的別名when。

alias when=while

4、執行大括號展開,比如h{a,i}t展開爲hat或hit。

5、將單詞開頭處的波浪號(~)替換成用戶的根目錄$HOME。

6、將任何開頭爲$符號的表達式,執行變量替換。

7、將反引號內的表達式,執行命令替換。

8、將$((string))的表達式進行算術運算。

9、從變量、命令和算術替換的結果中取出命令行,再次進行單詞切分,與步驟1不同的是,此時不再用元字符分隔單詞,而是使用$IFS分隔單詞。

10、對於*、?、[…]等符號,執行通配符展開,生成文件名。

11、將第一個單詞作爲命令,它可以是函數、內建命令和可執行文件。

12、在完成I/O重定向與其他類似事項後,執行命令。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章