1. 程式人生 > >關於Linux Shell的展開與匹配

關於Linux Shell的展開與匹配

花括號展開

在非引號內的內容,如果用花括號包括,而且裡面用逗號分隔(至少包含一個逗號,可以是空內容),這樣花括號裡的內容會被展開成用空格分開的一個列表,花括號前後可以緊隨字首和字尾(前後綴都是可選的)。 例如: echo {a,b,c} echo hello,{world,pig} echo rep{,,,,,}eat 注意花括號展開,字首不能是$,因為${...}在shell中是變數

波浪號展開

從波浪號~到第一個未被引號包含的斜槓/(如果沒有斜槓,則全部算上),作為波浪號字首。 在波浪號後面的字串作為一個可能的登入名:如果為空,被展開成該使用者的HOME變數,如果HOME變數未設定,則用使用者執行shell的主目錄替換。如果不為空,則按照該登入名的主目錄替換(原文:If this login name is the null string, the tilde is replaced with the value of the 
HOME shell variable. If HOME is unset, the home directory of the user executing the shell is substituted instead. Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.) 例如: echo ~   # 顯示$HOME內容 HOME=/bin && echo ~   # 顯示/bin unset HOME && echo ~   # 顯示當前使用者主目錄 echo ~root  # 顯示root使用者主目錄 波浪號還可以與加減號和數字,產生一個遍歷資料夾堆疊的效果(關於資料夾堆疊,參考dirs、pushd、popd幾個命令)。 echo ~+  # 顯示$PWD echo ~-  # 顯示$OLDPWD echo ~+2  # 顯示dirs中第3個內容,索引基於0 echo ~-3   # 顯示dirs中倒數第4個內容,索引基於0 如果無法展開,那就會原樣顯示,例如dir堆疊中只有1個內容,那麼~+1是無法展開的(這時只有~+0有效)。

Shell引數和變數展開

用$符號開始,後面接著變數名或者花括號括起來的變數名,如果是花括號內以歎號開頭,那麼就是變數名本身。 例如: echo $PWD    # 顯示PWD對應的值 echo ${PWD} # 顯示PWD對應的值 echo ${!PWD}   # 顯示“PWD”這個變數名,而不是它的值 echo ${!P*}      # 顯示所有以P開頭的環境變數名 如果一個變數名不存在,就建立它。 echo ${HELLO:=hello}  # 如果HELLO不存在,就用hello給它賦值,否則直接輸出$HELLO的值

命令替換

將一些命令執行後,結果替換到該命令語句中,可以用$()和``括住的方法 命令替換是可以巢狀的。 例如: echo `date` echo $(date) echo $(echo `date` |awk '{print $4}')

算術展開

放在$(( ))中的表示式會被計算,其中變數會被求值,例如: a=1 && b=3 && echo $(($a+$b)) 如果是數字,0開頭的8進位制,0x開頭的16進位制,其它進位制用Base#number的方式 可支援2~64進位制,如果進位制小於等於36,可以用a-z或A-Z表示10-35,如果進位制大於36,則a-z表示10-35,A-Z表示36-61,@表示62,_表示63 例如: echo $((16#32))  # 16進位制的32,輸出50 echo $((64#@_))  # 輸出4031 = 62 * 64 + 63 用$[]也可以算術展開,但是不要和測試條件[]混淆了 例如: echo $[1+4]

程序替換

>(LIST)或<(LIST) LIST是一個命令,它執行時會從一個FIFO或/dev/fd/xxx這樣的地方讀取(對應>(LIST))或輸出(對應<(LIST)),而這個FIFO或/dev/fd/xxx作為外面命令的一個引數。 例如: echo -e 'haha hehe\nhaha2 hehe2' >a.txt    # 生成了一個a.txt檔案,裡面有兩行 awk '{ print $2 }' <(cat a.txt)   # 先為<(cat a.txt)生成了一個/dev/fd/63,關聯到cat a.txt,也就是說cat a.txt的輸出都被定向到/dev/fd/63這個檔案了,然後外圍的命令執行的是awk '{ print $2 }' /dev/fd/63,這樣列印的就是hehe和hehe2。

字詞分隔

$IFS裡面的任何一個字元都可以作為分隔符,平時我們預設的就是回車、空格、tab符號。 (原文:The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting.

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words on these characters. If IFS is unset, or its value is exactly "'<space><tab><newline>'", the default, then any sequence of IFS characters serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters "space" and "Tab" are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IF whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.

Explicit null arguments ("""" or "''") are retained. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed. If a parameter with no value is expanded within double quotes, a null argument results and is retained.)

檔名展開

進行字詞分隔後,如果不指定-f選項,shell會搜尋"*","?","[",如果遇到了,就會認為是一個帶pattern的word,然後用字典序將符合的所有檔名替換過去,如果沒有檔名匹配:1 shell的nullglob選項關閉,則不進行檔名展開,保留word原樣;2 shell的nullglob開啟,則移除這個word。如果shell的nocaseglob選項開啟,則忽略大小寫。

當匹配檔名時(這裡指不包括資料夾),除非shell的dotglob被設定,否則.或./開頭的檔案都必須顯示指定,例如:

ls *   # 列出當前資料夾中所有不以"."開頭的檔案

ls .*  # 列出當前資料夾中所有以"."開頭的檔案

當匹配檔名時,"/"必需顯示匹配,例如:

ls ./* 和 ls ./*/*是不同的。

其它情況下,"."和普通字元一樣,例如:

*.txt和*txt都可以匹配a.txt

還有一個系統變數GLOBIGNORE,如果一個檔名匹配了一個pattern word,但是它也匹配了GLOBIGNORE,則它會被忽略,不過兩個特殊檔案一定會被忽略,就是"."和".."。

如果GLOBIGNORE開啟,那麼dotglob選項也會自動開啟,這樣會導致當你ls *時,其他以"."開頭的檔案也會被match,如果想忽略"."開頭的檔案,可以在GLOBIGNORE裡面新增一個".*"的匹配。如果GLOBIGNORE未設定,則dotglob關閉。

參考: