首頁 > 軟體

Linux下高效編寫Shell——Shell特殊字元匯總

2020-06-16 17:55:59

Linux下無論如何都是要用到shell命令的,在Shell的實際使用中,有程式設計經驗的很容易上手,但稍微有難度的是shell裡面的那些個符號,各種特殊的符號在我們編寫Shell指令碼的時候如果能夠用的好,往往能給我們起到事半功倍的效果,為此,特地將Shell裡面的一些符號說明羅列成對照表的形式,以便快速的查詢。看看你知道下表中哦你的哪些Shell符號呢?

Shell符號及各種解釋對照表:

Shell符號使用方法及說明
#

注釋符號(Hashmark[Comments])

1.在shell檔案的行首,作為shebang標記,#!/bin/bash;

2. 其他地方作為註釋使用,在一行中,#後面的內容並不會被執行,除非;

3. 但是用單/雙引號包圍時,#作為#號字元本身,不具有註釋作用。

;

作為多語句的分隔符(Command separator [semicolon])。

多個語句要放在同一行的時候,可以使用分號分隔。注意,有時候分號需要跳脫。

;;

連續分號(Terminator [double semicolon])。

在使用case選項的時候,作為每個選項的終結符。在Bash version 4+ 的時候,還可以使用[;;&], [;&]

.

點號(dot command [period])。

1. 相當於bash內建命令source,如:

  1. #!/bin/bash
  2. . data-file
  3. #包含data-file;

2. 作為檔名的一部分,在檔名的開頭,表示該檔案為隱藏檔案,ls一般不顯示出來(ls -a 可以顯示);

3. 作為目錄名,一個點代表當前目錄,兩個點號代表上層目錄(當前目錄的父目錄)。注意,兩個以上的點不出現,除非你用引號(單/雙)包圍作為點號字元本身;

4. 正規表示式中,點號表示任意一個字元。

"

雙引號(partial quoting [double quote])。

部分參照。雙引號包圍的內容可以允許變數擴充套件,也允許跳脫字元的存在。如果字串內出現雙引號本身,需要跳脫,因此不一定雙引號是成對的。

'

單引號(full quoting [single quote])。

單引號括住的內容,被視為單一字串,引號內的禁止變數擴充套件,所有字元均作為字元本身處理(除單引號本身之外),單引號必須成對出現。

,

逗號(comma operator [comma])。

1. 用在連線一連串的數學表示式中,這串數學表示式均被求值,但只有最後一個求值結果被返回。如:

  1. #!/bin/bash
  2. let t1=((a=5+1, b=7+2))
  3. echo t1=$t1, a=$a, b=$b
  4. ## 這個$t1=$b;

2. 用於引數替代中,表示首字母小寫,如果是兩個逗號,則表示全部小寫,注意,這個特性在bash version 4的時候被新增的。例子:

  1. a="ATest"
  2. echo ${a,}
  3. echo ${a,,}
  4. ## 前面輸出aTest,後面輸出的是atest。

反斜線,反斜桿(escape [backslash])。

1. 放在特殊符號之前,跳脫特殊符號的作用,僅表示特殊符號本身,這在字串中常用;

2. 放在一行指令的最末端,表示緊接著的回車無效(其實也就是跳脫了Enter),後繼新行的輸入仍然作為當前指令的一部分。

/

斜線,斜桿(Filename path separator [forward slash])。

1.作為路徑的分隔符,路徑中僅有一個斜桿表示根目錄,以斜桿開頭的路徑表示從根目錄開始的路徑;

2.在作為運算子的時候,表示除法符號。如:a=4/2

`

反引號,後引號(Command substitution[backquotes])。

命令替換。這個引號包圍的為命令,可以執行包圍的命令,並將執行的結果賦值給變數。如:a=`dirname '/tmp/x.log'` 。後面dirname返回的結果會賦值給a,注意,此處Mitchell特地使用了反引號和單引號,注意區別。

:

冒號(null command [colon])。

空命令,這個命令什麼都不做,但是有返回值,返回值為0(即:true)。這個命令的作用非常奇妙。

1. 可做while死迴圈的條件;

2. 在if分支中作為預留位置(即某一分支什麼都不做的時候);

3. 放在必須要有兩元操作的地方作為分隔符,如:: ${username=`whoami`}

4. 在引數替換中為字串變數賦值,在重定向操作(>)中,把一個檔案長度截斷為0(:>>這樣用的時候,目標存在則什麼都不做),這個只能在普通檔案中使用,不能在管道,符號連結和其他特殊檔案中使用;

5. 甚至你可以用來註釋(#後的內容不會被檢查,但:後的內容會被檢查,如果有語句如果出現語法錯誤,則會報錯);

6. 你也可以作為域分隔符,比如環境變數$PATH中,或者passwd中,都有冒號的作為域分隔符的存在;

7. 你也可以將冒號作為函數名,不過這個會將冒號的本來意義轉變(如果你不小心作為函數名,你可以使用unset -f : 來取消function的定義)。

!

感嘆號(reverse (or negate) [bang],[exclamation mark])。

取反一個測試結果或退出狀態。

1. 表示反邏輯,比如後面的!=,這個是表示不等於;

2. 表示取反,如:ls a[!0-9] #表示a後面不是緊接一個數位的檔案;

3. 在不同的環境裡面,感嘆號也可以出現在間接變數參照裡面;

4. 在命令列中,可以用於歷史命令機制的呼叫,你可以試試!$,!#,或者!-3看看,不過要注意,這點特性不能在指令碼檔案裡面使用(被禁用)。

*

星號(wildcard/arithmetic operator[asterisk])。

1. 作為匹配檔名擴充套件的一個萬用字元,能自動匹配給定目錄下的每一個檔案;

2. 正規表示式中可以作為字元限定符,表示其前面的匹配規則匹配任意次;

3. 算術運算中表示乘法。

**

雙星號(double asterisk)。算術運算中表示求冪運算。

?

問號(test operator/wildcard[Question mark])。

1. 表示條件測試;

2. 在雙括號內表示C風格的三元操作符((condition?true-result:false-result));

3. 引數替換表示式中用來測試一個變數是否設定了值;

4. 作為萬用字元,用於匹配檔名擴充套件特性中,用於匹配單個字元;

5. 正規表示式中,表示匹配其前面規則0次或者1次。

$

美元符號(Variable substitution[Dollar sign])。

1. 作為變數的前導符,用作變數替換,即參照一個變數的內容,比如:echo $PATH

2. 在正規表示式中被定義為行末(End of line)。

${}

引數替換(Variable substitution)。

用於在字串中表示變數。

$‘...’

參照內容展開,執行單引號內的跳脫內容(單引號原本是原樣參照的),這種方式會將引號內的一個或者多個[]跳脫後的八進位制,十六進位制值展開到ASCII或Unicode字元。

$*

$@

位置引數(Positional Parameters)。

這個在使用指令碼檔案的時候,在傳遞引數的時候會用到。兩者都能返回撥用指令碼檔案的所有引數,但$*是將所有引數作為一個整體返回(字串),而$@是將每個引數作為單元返回一個參數列。注意,在使用的時候需要用雙引號將$*,$@括住。這兩個變數受到$IFS的影響,如果在實際應用中,要考慮其中的一些細節。

$#

表示傳遞給指令碼的引數數量。

$?

此變數值在使用的時候,返回的是最後一個命令、函數、或指令碼的退出狀態碼值,如果沒有錯誤則是0,如果為非0,則表示在此之前的最後一次執行有錯誤。

$$

進程ID變數,這個變數儲存了執行當前指令碼的進程ID值。

()

圓括號(parentheses)。

1, 命令組(Command group)。由一組圓括號括起來的命令是命令組,命令組中的命令實在子shell(subshell)中執行。因為是在子shell內執行,因此在括號外面是沒有辦法獲取括號內變數的值,但反過來,命令組內是可以獲取到外面的值,這點有點像區域性變數和全域性變數的關係,在實作中,如果碰到要cd到子目錄操作,並在操作完成後要返回到當前目錄的時候,可以考慮使用subshell來處理;

2. 用於陣列的初始化。

{x,y,z,...}

花括號擴充套件(Brace Expansion)。

在命令中可以用這種擴充套件來擴充套件參數列,命令將會依照列表中的括號分隔開的模式進行匹配擴充套件。注意的一點是,這花括號擴充套件中不能有空格存在,如果確實有必要空格,則必須被跳脫或者使用引號來參照。例子:echo {a,b,c}-{ d," e",' f'}

{a..z}

在Bash version 3時新增了這種花括號擴充套件的擴充套件,可以使用{A..Z}表示A-Z的所有字元列表,這種方式的擴充套件Mitchell測試了一下,好像僅適用於A-Z,a-z,還有數位{最小..最大}的這種方式擴充套件。

{}

程式碼塊(curly brackets)。

這個是匿名函數,但是又與函數不同,在程式碼塊裡面的變數在程式碼塊後面仍能存取。注意:花括號內側需要有空格與語句分隔。另外,在xargs -i中的話,還可以作為文字的預留位置,用以標記輸出文字的位置。

{} ;

這個{}是表示路徑名,這個並不是shell內建的,現在接觸到的情況看,好像只用在find命令裡。注意後面的分號,這個是結束find命令中-exec選項的命令序列,在實際使用的時候,要跳脫一下以免被shell理解錯誤。

[]

中括號(brackets)。

1. 測試的表示,Shell會測試在[]內的表示式,需要注意的是,[]是Shell內建的測試的一部分,而非使用外部命令/usr/bin/test的連結;

2. 在陣列的上下文中,表示陣列元素,方括號內填上陣列元素的位置就能獲得對應位置的內容,如:

  1. Array[1]=xxx
  2. echo ${Array[1]};

3. 表示字元集的範圍,在正表示式中,方括號表示該位置可以匹配的字元集範圍。

[[]]

雙中括號(double brackets)。

這個結構也是測試,測試[[]]之中的表示式(Shell的關鍵字)。這個比單中括號更能防止指令碼裡面的邏輯錯誤,比如:&&,||,<,>操作符能在一個[[]]裡面測試通過,但是在[]卻不能通過。[[]]裡面沒有檔名擴充套件(filename expansion)或是詞分隔符(Word splitting),但是可以用引數擴充套件(Parameter expansion)和命令替換(command substitution)。不用檔名萬用字元和像空白這樣的分隔符。注意,這裡面如果出現了八進位制,十六進位制等,shell會自動執行轉換比較。

$[...]

詞表達表示整數擴充套件(integer expansion)。

在方括號裡面執行整數表示式。例:

  1. a=3
  2. b=7
  3. echo $[$a+$b]
  4. echo $[$a*$b]
  5. ##返回是10和21
(())

雙括號(double parentheses)。

表示整數擴充套件(integer expansion)。功能和上面的$[]差不多,但是需要注意的是,$[]是會返回裡面表示式的值的,而(())只是執行,並不會返回值。兩者執行後如果變數值發生變化,都會影響到後繼程式碼的執行。可對變數賦值,可以對變數進行一目操作符操作,也可以是二目,三目操作符。

>

&<

>&

>>

<

<>

重定向(redirection)。

scriptname >filename 重定向scriptname的輸出到檔案filename中去,如果檔案存在則覆蓋;

command &>filename 重定向command的標準輸出(stdout)和標準錯誤(stderr)到檔案filename中;

command >&2 把command的標準輸出(stdout)重定向到標準錯誤(stderr)中;

scriptname >>filename 把scriptname的輸出(同>)追加到檔案filenmae中,如果檔案不存在則建立。

[i]<>filename 開啟filename這個檔案用來讀或者寫,並且給檔案指定i為它的檔案描述符(file descriptor),檔案不存在就會建立。

(command)>

<(command)

這是進程替換(Process Substitution)。

使用的時候注意,括號和<,>之間是不能有空格的,否則報錯。其作用有點類似通道,但和管道在用法上又有些不同,管道是作為子進程的方式來執行的,這個命令會在/dev/fd/下面產生類似/dev/fd/63,/dev/fd/62這類臨時檔案,用來傳遞資料。

Mitchell個人猜測之所以用這種方法來傳遞,是因為前後兩個不屬於同一個進程,因此需要用共用檔案的方式來傳遞資料(這麼說其實管道也應該有同樣的檔案?)。網上有人說這個只是共用檔案而已,但是經過測試,發現雖然有/dev/fd/63這樣的檔案產生,但是這個檔案其實是指向pipe:[43434]這樣的通道的連結。

<<

雙小於號(here-document[double less then marks])。

這個也被稱為Here-document,用來將後繼的內容重定向到左側命令的stdin中。<<可以節省格式化時間,別且使命令執行的處理更容易。在實作的時候只需要輸入<<和終止標誌符,而後(一般是回車後)你就可以輸入任何內容,只要在最後的新行中輸入終止標誌符,即可完成資料的匯入。使用here-document的時候,你可以保留空格,換行等。如果要讓shell指令碼更整潔一點,可以在<<和終止符之間放上一個連字元(-)。

<<<

三個小於號(here-strings)。Here-字串和Here-document類似,here-strings語法:command [args] <<<["]$word["];$word會展開並作為command的stdin。

<

>

小於,大於號(ASCII Comparison)。

ASCII比較,進行的是變數的ASCII比較,字串?數位?呃...這個...不就是ASCII比較麼?

<...>

詞界符(word boundary)。

這個是用在正規表示式中的一個特殊分隔符,用來標記單詞的分界。比如:the會匹配there,another,them等等,如果僅僅要匹配the,就可以使用這個詞界符,<the>就只能匹配the了。

|

管道(pipe)。管道是Linux,Unix都有的概念,是非常基礎,也是非常重要的一個概念。它的作用是將管道前(左邊)的命令產生的輸出(stdout)作為管道後(右邊)的命令的輸入(stdin)。如:ls | wc l,使用管道就可以將命令連線在一起。注意:管道是每一個進程的標準輸出都會作為下一個命令的標準輸入,期間的標準輸出不能跨越管道作為後繼命令的標準輸入,如: cat filename | ls -al | sort 。想想這個的輸出? 同時,管道是以子進程來執行的,所以管道並不能引起變數改變。

>|

強制重定向(force redirection)。

這會強制重寫已經存在的檔案。

&

與號(Run job in background[ampersand])。

如果命令後面跟上一個&符號,這個命令將會在後台執行。有的時候,指令碼中在一條在後台執行的命令可能會引起指令碼掛起,等待輸入,出現這種情況可以在原有的指令碼後面使用wait命令來修復。

&&

||

邏輯操作符(logical operator)。

在測試結構中,可以用這兩個操作符來進行連線兩個邏輯值。||是當測試條件有一個為真時返回0(真),全假為假;&&是當測試條件兩個都為真時返回真(0),有假為假。

-

減號,連字元(Hyphen/minus/dash)。

1. 作為選項,字首[option, prefix]使用。用於命令或者過濾器的選項標誌;操作符的字首。如:

  1. ## COMMAND -[選項列表]
  2. ls -al
  3. sort -dfu $file
  4. set-- $variable
  5. if[ $file -ot $file2 ]
  6. then
  7. echo "$file is older than $file2."
  8. fi

2. 用於stdin或者stdout的重定向的源或目的[dash].在tar沒有bunzip2的程式修補程式時,我們可以這樣: bunzip2 linux-2.6.13.tar.bz2 | tar xvf - 。將前面解壓的資料作為tar的標準輸入(這裡使用一個-表示)

注意:在實作的時候,如果檔名是以[-]開頭的,那麼在加上這個作為定向操作符的時候,可能會出錯,此時應該為檔案加上合適的字首路徑,以避免這種情況發生,同樣的,在echo變數的時候,如果變數是以[-]開始,那麼可能也會產生意想不到的結果,為了保險起見,可以使用雙引號參照標量:

  1. var="-n"
  2. echo $var
  3. ## 試試看有什麼輸出?

還有,這種表示方法不是Bash內建的,要達到此點的這種效果,需要看你使用的軟體是否支援這種操作;

3. 表示先前的工作目錄(previous working directory),因此,如果你cd到其他目錄下要放回前一個路徑的時候,可以使用cd -來達到目的,其實,這裡的[-]使用的是環境變數的$OLDPWD,注意:這裡的[-]和前一點是不同的;

4. 減號或者負號,用在算術操作中。

=

等號(Equals)。

1. 賦值操作,給變數賦值,麼有空格在等號兩側;

2. 在比較測試中作為比較符出現,這裡要注意,如果在中括號中作為比較出現,需要有空格符在等號左右兩側。

+

加號(Plus)。

1. 算術操作符,表示加法;

2. 在正規表示式中,表示的是其前的這個匹配規則匹配最少一次;

3.在命令或過濾器中作為選項標記,在某些命令或者內建命令中使用+來啟用某些選項,使用-來禁止;

4. 在引數替換(parameter substitution)中,+字首表示替代值(當變數為空的時候,使用+後面的值)

%

百分號(modulo[percent sign])。

1.在算術運算中,這個是求模操作符,即兩個數進行除法運算後的餘數;

2. 在引數替換(parameter substitution)中,可以作為模式匹配。例子:

  1. p=b*9
  2. var="abcd12345abc479"
  3. echo ${var%p}, ${var%%p}
  4. ##從右邊開始查詢(想想從左是那個符號?)
  5. ##任何在b和9之間的內容(含)
  6. ##第一個是找到最短的符合匹配項
  7. ##後一個是找最大符合的匹配項(貪婪匹配?)
~

波浪號(Home directory[tilde])。

這個和內部變數$HOME是一樣的。預設表示當前使用者的家目錄(主目錄),這個和~/效果一致,如果波浪號後面跟使用者名稱,表示是該使用者的家目錄。

~+

當前的工作目錄(current working directory)。

這個和內建變數$PWD一樣。

~-

前一個工作目錄(previous working directory)。

這個和內部變數$OLDPWD一致,之前的[-]也一樣。

=~

Bash 版本3中有介紹,這個是正規表示式匹配。可用在[[]]測試中,比如:

  1. var="this is a test message."
  2. [["$var"=~ tf*message ]]&& echo "Sir. Found that."|| echo "Sorry Sir. No match be found."
  3. ##你可以修改中間的正規表示式匹配項,正規表示式可以但不一定需要使用雙引號括起來。
^

脫字元(caret)。

1. 在正規表示式中,作為一行的行首(beginning-of-line)位置標誌符;

2. 在引數替換(Parameter substitution)中,這個用法有兩種,一個脫字元(${var^}),或兩個(${var^^}),分別表示第一個字母大寫,全部大寫的意思(Bash version >=4)。

空白

空白符(Whitespace)。

空白符不僅僅是指空格(spaces),還包括製表符(tabs),空行(blank lines),或者這幾種的組合。可用做函數的分隔符,分隔命令或變數,空行不會影響指令碼的行為,因此可以用它來規劃指令碼程式碼,以增加可讀性,在內建的特殊變數$IFS可以用來針對某些命令進行輸入的引數進行分割,其預設就是空白符。在字串或變數中如果有空白符,可以使用引號來規避可能的錯誤。

怎樣,你有多少是了解的呢?Mitchell在開始的Shell指令碼時候,發現在這裡面有好多都是不認識呢。

說明:因為涉及到翻譯,文中內容不一定完全翻譯準確,如果你發現有錯誤的地方,還請包涵指正。

參考:

  1. 本文主要內容來源:Advanced Bash-Scripting Guide
  2. 對話 UNIX: !$#@*%
  3. wikipedia的Here文件

參考內容為本篇成文之際給予Mitchell幫助較大的文章,在整個過程中還有很多網站資訊給我提供了幫助,在此對他們的作者的無私貢獻表示感謝!

本文永久更新連結地址http://www.linuxidc.com/Linux/2015-08/121217.htm


IT145.com E-mail:sddin#qq.com