3.shell 基本特性之~ shell展開(kāi)詳解

第 3 章目錄:

3.1 shell 語(yǔ)法
3.2 shell 命令
3.3 shell 函數(shù)
3.4 shell 參數(shù)
3.5 shell 展開(kāi)
3.6 重定向
3.7 命令執(zhí)行
3.8 shell 腳本

本文件內(nèi)容為 "3.5 shell 展開(kāi)"


3.5 小節(jié)目錄:

3.5.1 花括號(hào)展開(kāi) 對(duì)花括號(hào)中的表達(dá)式的展開(kāi)
3.5.2 波浪線(xiàn)展開(kāi)
3.5.3 shell 參數(shù)展開(kāi)
3.5.4 命令替換 把命令的輸出當(dāng)做參數(shù)使用
3.5.5 算術(shù)展開(kāi) 如何在 shell 表達(dá)式中進(jìn)行算術(shù)運(yùn)算
3.5.6 過(guò)程替換 一種對(duì)命令進(jìn)行讀寫(xiě)的方法
3.5.7 單詞分割 展開(kāi)結(jié)果是如何分割成獨(dú)立的參數(shù)的
3.5.8 文件名展開(kāi)
3.5.9 引用刪除

命令行被分割為 token 之后,就開(kāi)始進(jìn)行展開(kāi)。一共有 7 種展開(kāi):

1,花括號(hào)展開(kāi)
2,波浪線(xiàn)展開(kāi)
3,參數(shù)和變量展開(kāi)
4,命令替換
5,算術(shù)展開(kāi)
6,單詞分割
7,文件名展開(kāi)

展開(kāi)的順序是:

1,花括號(hào)展開(kāi)
2,波浪線(xiàn)展開(kāi)
3,參數(shù),變量,算術(shù)展開(kāi)和命令替換(在支持過(guò)程替換的系統(tǒng)上,過(guò)程替換也在這里進(jìn)行)
4,單詞分割
5,文件名展開(kāi)

只有花括號(hào)展開(kāi),單詞分割,文件名展開(kāi)能改變展開(kāi)結(jié)果的單詞個(gè)數(shù)。

其他展開(kāi)一般把一個(gè)單詞展開(kāi)為另一個(gè)單詞,有兩個(gè)例外情況:'"$@"' 和 '"${NAME[@]}"'。

所有展開(kāi)完成后,進(jìn)行引用刪除

3.5.1 花括號(hào)展開(kāi)


在花括號(hào)內(nèi),可以是以逗號(hào)分隔的字符串,或者是一個(gè)序列表達(dá)式。在花括號(hào)前后,可以跟前綴和后綴。

花括號(hào)展開(kāi)支持嵌套,展開(kāi)的字符串是無(wú)序的,從左到右的順序被保留。

1,逗號(hào)分隔

# echo a{d,c,b}e
ade ace abe

前綴 a 和 后綴 e 與展開(kāi)結(jié)果的每一個(gè)字符串結(jié)合生成最終結(jié)果。

2,序列表達(dá)式

序列表達(dá)式的語(yǔ)法是:
'{X..Y[..INCR]}'

X,Y 是數(shù)字或單個(gè)字符,INCR 是步進(jìn)。

當(dāng) X,Y 是數(shù)字時(shí),展開(kāi)為 X 到 Y 的所有數(shù)字。數(shù)字可加前綴 0,如 01,001,使展開(kāi)結(jié)果保持相同的寬度。

當(dāng) X 或 Y 以 0 開(kāi)頭時(shí),shell 嘗試將生成結(jié)果保持相同寬度。必要時(shí)以 0 進(jìn)行填充。

{01..100} 生成 001, 002, ..., 100

步進(jìn):
{1..10..2} 生成 1 3 5 7 9

當(dāng) X,Y 是字母時(shí),按字典序展開(kāi)。X,Y 必須是相同類(lèi)型。當(dāng)給出步進(jìn)時(shí),相鄰字母的距離為步進(jìn)的距離。默認(rèn)步進(jìn)為 1 或 -1(看具體情況)。

{a..g..2} 生成 a c e g

花括號(hào)展開(kāi)在其它展開(kāi)之前進(jìn)行,任何對(duì)于其它展開(kāi)有特殊意義的字符都被保留。

在進(jìn)行花括號(hào)展開(kāi)時(shí),bash 對(duì)于花括號(hào)的上下文和括號(hào)內(nèi)的文本內(nèi)容不做任何的語(yǔ)法解釋。

為避免與參數(shù)展開(kāi)產(chǎn)生沖突,字符串 '${' 不被認(rèn)為需要做花括號(hào)展開(kāi)。

要進(jìn)行正確的花括號(hào)展開(kāi),必須包含未被引用(unquoted)的 '{' 和 '}'。并且在括號(hào)中,至少有一個(gè)未被引用的 ',' 或者一個(gè)有效的“序列表達(dá)式”。

書(shū)寫(xiě)不正確的花括號(hào)展開(kāi)保留原樣。

把 '{' 和 ',' 引用起來(lái),可避免被認(rèn)為是花括號(hào)展開(kāi)的一部分。為避免與參數(shù)展開(kāi)產(chǎn)生沖突,字符串 '${' 不被認(rèn)為需要做花括號(hào)展開(kāi)。

這個(gè)構(gòu)造典型的應(yīng)用場(chǎng)景是,當(dāng)字符串前綴太長(zhǎng)的時(shí)候,比如創(chuàng)建多個(gè)包含絕對(duì)路徑的文件時(shí),使用花括號(hào)展開(kāi)可以簡(jiǎn)化命令行語(yǔ)句,如:

mkdir /usr/local/src/bash/{old,new,dist,bugs}

chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} # 兩個(gè)子目錄

3.5.2 波浪線(xiàn)展開(kāi)


如果一個(gè)單詞以未被引用的 '~' 開(kāi)頭,這個(gè)單詞所有到斜線(xiàn) '/'(如果有得話(huà)) 為止的字符被認(rèn)為是一個(gè) 波浪線(xiàn)前綴字符串(TILDE-PREFIX)。

如果在 “波浪線(xiàn)前綴字符串” 中沒(méi)有被引號(hào)引用的字符,那么所有波浪線(xiàn)之后的字符組成的字符串被當(dāng)做可能的 LOGIN NAME 對(duì)待。

如果 LOGIN NAME 是空字符串,'~' 被替換為 'HOME' 變量的值。
如果 'HOME' 變量沒(méi)有設(shè)置,則替換為執(zhí)行 shell 的用戶(hù)的家目錄。
否則,'~' 被替換為與 登錄名 關(guān)聯(lián)的家目錄。

$ echo $HOME #HOME 非空
/Users/guli

$ echo ~ #打印當(dāng)前用戶(hù)家目錄
/Users/guli

$ echo ~guest #打印guest用戶(hù)家目錄
/Users/Guest

$ echo ~root #打印root用戶(hù)家目錄
/var/root

如果 波浪線(xiàn)前綴字符串 是 '~+',被替換為 'PWD' 變量的值。

如果是 '~-',被替換為 'OLDPWD' 變量的值(如果存在的話(huà))。

如果 波浪線(xiàn)前綴字符串 是一個(gè)數(shù)字,數(shù)字前跟著一個(gè) '+' 或 '-',如 '~+N',則被替換為 目錄棧 的相應(yīng)順序的元素。等同于 dirs +/-N 的效果。

如果 '+' 或 '-' 沒(méi)有給出,默認(rèn)為 '+'。

如果 登錄名 是無(wú)效的,或者波浪線(xiàn)展開(kāi)失敗,則保留原樣。

$ echo ~guset #登錄名 guset 是無(wú)效的
~guset

每個(gè)變量賦值會(huì)檢查緊跟在 ':' 或第一個(gè) '=' 后面是否有未被引號(hào)引用的 '~'。如果有,會(huì)進(jìn)行波浪線(xiàn)展開(kāi)。所以,我們可以通過(guò)這種方式賦值給 'PATH','MAILPATH','CDPATH',shell 會(huì)用展開(kāi)后的結(jié)果賦值給變量。

下面是 bash 中的波浪線(xiàn)展開(kāi)的示例:

'~'
展開(kāi)為 '$HOME' 的值

'~/foo'
展開(kāi)為 '$HOME/foo'

'~fred/foo'
展開(kāi)為 用戶(hù)fred的及目錄的子目錄foo: /home/fred/foo

'~+/foo'
展開(kāi)為 '$PWD/foo'

'~-/foo'
展開(kāi)為 '{OLDPWD-'~-'}/foo'

'~N'
等同于執(zhí)行 'dirs +N' 的結(jié)果

'~+N'
等同于執(zhí)行 'dirs +N' 的結(jié)果

'~-N'
等同于執(zhí)行 'dirs -N' 的結(jié)果

3.5.3 Shell 參數(shù)展開(kāi)


'$' 符號(hào)引入了三種 shell 展開(kāi),包括 “參數(shù)展開(kāi)”,“命令替換” 和 “算術(shù)表達(dá)式”。

參數(shù)名或參數(shù)符號(hào)可以用花括號(hào)括起來(lái),使緊跟在參數(shù)名后面的字符與之分隔,這些字符與展開(kāi)的結(jié)果可共同構(gòu)成最后字符串。如 ${PATH}:/path/to/..

在參數(shù)展開(kāi)中使用花括號(hào)時(shí),'{' 是開(kāi)始符號(hào),右邊第一個(gè) '}' 是結(jié)束符號(hào)。
'}' 不能被轉(zhuǎn)義,或被引號(hào)引用,也不能在一個(gè)嵌套的 “算術(shù)表達(dá)式”,或 “命令替換”,或者 “參數(shù)展開(kāi)”之中。

參數(shù)展開(kāi)的基本的形式是 ${PARAMETER},整體被替換為 PARAMETER 的值。如果 PARAMETER 是位置參數(shù),而且由兩個(gè)及以上的數(shù)字表示,這時(shí)必須使用花括號(hào):${10}。另外當(dāng) PARAMETER 與其它字符相鄰連接時(shí),也必須使用花括號(hào):${Var}lala。

如果 PARAMETER 的第一個(gè)字符是 "!",會(huì)進(jìn)行“間接變量展開(kāi)”。bash 使用 "!" 之后的部分作為變量名,變量進(jìn)行展開(kāi),變量展開(kāi)結(jié)果作為被引用的對(duì)象再進(jìn)行一次展開(kāi)。"!" 符號(hào)必須緊跟在左括號(hào) "{" 后面。但是 ${!PREFIX*} 和 ${!NAME[@]} 是例外,在下面會(huì)介紹。

在下面將要介紹的例子中,WORD 可進(jìn)行 “波浪線(xiàn)展開(kāi)”,“參數(shù)展開(kāi)”,“命令替換” 以及 “算術(shù)展開(kāi)”。也就是說(shuō),WORD 可以是 $VAR,$(CMD),$(EXPR),~ 形式的。
如果 WORD 是字符串,就不會(huì)做展開(kāi),在這里不是作為變量名使用的。

當(dāng)不進(jìn)行子字符串展開(kāi)時(shí),使用下面的形式,bash 會(huì)測(cè)試 PARAMETER
是否是 unset,或是否是空字符串(null)。
如果刪除冒號(hào) ':',只會(huì)測(cè)試 PARAMETER 是否是 unset(是否存在)。

'${PARAMETER:-WORD}'

如果 PARAMETER 是 unset 或者 null,最終展開(kāi)結(jié)果為 WORD 的展開(kāi)(普通字符串的展開(kāi)結(jié)果是原字符串保持不變,這里不是取 WORD 的值為最終結(jié)果)。否則,使用 PARAMETER 的變量值為最終結(jié)果。

'${PARAMETER:=WORD}'

如果 PARAMETER 是 unset 或者 null,將 WORD 的展開(kāi)結(jié)果賦值給PARAMETER(不是 WORD 的參數(shù)值),最終結(jié)果為 PARAMETER 的值。但是“位置參數(shù)”和“特殊參數(shù)”不可通過(guò)這種方式賦值。

'${PARAMETER:?WORD}'

如果 PARAMETER 是 unset 或者 null,將 WORD 的展開(kāi)結(jié)果(如果未給出 WORD,會(huì)有一條消息)寫(xiě)入標(biāo)準(zhǔn)錯(cuò)誤輸出以及 shell,如果 shell 是非交互式的,就退出 shell。否則,使用 PARAMETER 的變量值最終結(jié)果。

'${PARAMETER:+WORD}'

如果 PARAMETER 是 unset 或者 null,結(jié)果是 nothing。否則 WORD 的展開(kāi)結(jié)果為最終結(jié)果。

'${PARAMETER:OFFSET}'
'${PARAMETER:OFFSET:LENGTH}'

1,當(dāng) PARAMETER 是普通變量時(shí),以字符為單位對(duì)參數(shù)值做截取。

OFFSET: 從0開(kāi)始的位移,截取從位移處開(kāi)始。
LENGTH: 截取的字符個(gè)數(shù)。如果沒(méi)有寫(xiě)明 LENGTH,即截取從位移處到最后一個(gè)
字符。

OFFSET 和 LENGTH 是“算數(shù)表達(dá)式”。這種展開(kāi)可被稱(chēng)為“子字符串展開(kāi)”。

LENGTH 必須大于等于1,當(dāng)OFFSET是負(fù)數(shù)時(shí),表示從參數(shù)值的尾部向前截取。

2,當(dāng) PARAMETER 是位置參數(shù)時(shí),比如'@',表示從OFFSET處開(kāi)始的LENGTH個(gè)位置參數(shù)。

3,當(dāng) PARAMETER 是以@或*為下標(biāo)的數(shù)組時(shí),表示從'${PARAMETER[OFFSET]}'開(kāi)始的 LENGTH 個(gè)數(shù)組變量。

OFFSET 如果是負(fù)數(shù),它的計(jì)數(shù)從數(shù)組最大下標(biāo)+1的地方計(jì)算。

-1 是最后一個(gè)元素的索引

“子字符串展開(kāi)”用到數(shù)組上時(shí)會(huì)產(chǎn)生未知的結(jié)果。

注意:負(fù)數(shù)的 offset 必須用空格與冒號(hào)':'隔開(kāi),以免和“:-展開(kāi)”混淆。

對(duì)于字符串,索引從 0 開(kāi)始。(0-based)

對(duì)于位置參數(shù),索引從 1 開(kāi)始。(1-based)

對(duì)于數(shù)組,索引從 0 開(kāi)始。(0-based)

'${!PREFIX*}'
'${!PREFIX@}'

展開(kāi)結(jié)果為所有以 PREFIX 為前綴的變量的名字。這些變量名以"IFS"變量的第
一個(gè)字符作為分隔符。

如果用的是@,而且在雙引號(hào)中展開(kāi),每個(gè)變量名展開(kāi)為獨(dú)立的單詞。

如果用的是*,而且在雙引號(hào)中展開(kāi),所有變量名展開(kāi)為一個(gè)單詞。

#  echo ${!BASH@}
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION

# for i in "${!BASH*}"; do echo "haha"; done
haha   <=== 展開(kāi)為1個(gè)單詞,所以打印一次。


# for i in "${!BASH@}"; do echo "haha"; done
haha  <=== 展開(kāi)為獨(dú)立個(gè)單詞,所以打印多次。
haha
haha
haha
haha
haha
haha
haha
haha
haha
haha
haha
haha

'${!NAME[@]}'
'${!NAME[*]}'

如果 NAME 是數(shù)組變量,展開(kāi)為數(shù)組索引(key)的列表。

如果 NAME 不是數(shù)組變量,當(dāng)變量存在時(shí)展開(kāi)為0。

如果用的是@,而且在雙引號(hào)中展開(kāi),每個(gè)key展開(kāi)為獨(dú)立的單詞。

'${#PARAMETER}'

展開(kāi)為參數(shù)值的長(zhǎng)度。

如果參數(shù)是“*”或者“@”,展開(kāi)為位置參數(shù)的個(gè)數(shù)。

當(dāng)參數(shù)是以@或*為下標(biāo)的數(shù)組,展開(kāi)為數(shù)組中元素的個(gè)數(shù)。

'${PARAMETER#WORD}'
'${PARAMETER##WORD}'

將 WORD 的展開(kāi)結(jié)果作為匹配模式(如同文件名展開(kāi)中的通配符匹配),去匹配參數(shù)值的開(kāi)始部分,匹配到的部分將被刪除。

使用“#”,表示最短匹配,

使用“##”,表示最長(zhǎng)匹配。

如果參數(shù)是“*”或者“@”,對(duì)每個(gè)位置參數(shù)做上面的操作,

當(dāng)參數(shù)是以@或*為下標(biāo)的數(shù)組,對(duì)每個(gè)數(shù)組變量做如上的操作。

'${PARAMETER%WORD}'
'${PARAMETER%%WORD}'

將 WORD 的展開(kāi)結(jié)果作為匹配模式(如同文件名展開(kāi)中的通配符匹配),從參數(shù)值的尾部做匹配,匹配到的部分將被刪除。

使用“#”,表示最短匹配,

使用“##”,表示最長(zhǎng)匹配。

如果參數(shù)是“*”或者“@”,對(duì)每個(gè)位置參數(shù)做上面的操作,

當(dāng)參數(shù)是以@或*為下標(biāo)的數(shù)組,對(duì)每個(gè)數(shù)組變量做如上的操作。最終結(jié)果為所有被處理過(guò)的參數(shù)的列表。

'${PARAMETER/PATTERN/STRING}'

這個(gè)可視為上面兩個(gè)展開(kāi)的增強(qiáng)版。PATTERN 的展開(kāi)結(jié)果作為匹配模式,對(duì)參數(shù)的值做最長(zhǎng)匹配,匹配的部分替換為 STRING。

一般只有第一個(gè)被匹配的部分才替換為 STRING,但如果 PATTERN 以 '/' 開(kāi)頭,則所有匹配的部分都將被替換。

如果 PATTERN 以 '#' 開(kāi)頭,它必須從參數(shù)值的開(kāi)始部分進(jìn)行匹配。

如果 PATTERN 以 '%' 開(kāi)頭,它必須從參數(shù)值的尾部進(jìn)行匹配。

如果 STRING=null,匹配的部分將被刪除,而且 PATTERN 后面的 '/' 被忽略。

如果參數(shù)是“*”或者“@”,對(duì)每個(gè)位置參數(shù)做上面的操作,

當(dāng)參數(shù)是以@或*為下標(biāo)的數(shù)組,對(duì)每個(gè)數(shù)組變量做如上的操作。最終結(jié)果為所有被處理過(guò)的參數(shù)的列表。

'${PARAMETER^PATTERN}'
'${PARAMETER^^PATTERN}'
'${PARAMETER,PATTERN}'
'${PARAMETER,,PATTERN}'

這個(gè)展開(kāi)用來(lái)修改參數(shù)值的字符的大小寫(xiě)。

PATTERN 的展開(kāi)結(jié)果作為匹配模式

^ 將匹配的第一個(gè)字母的小寫(xiě)改為大寫(xiě)。

, 將匹配的第一個(gè)字母的大寫(xiě)改為小寫(xiě)。

^^ 將匹配的所有字母改為大寫(xiě)

,, 將匹配的所有字母改為小寫(xiě)

如果沒(méi)有給出 PATTERN,則默認(rèn)將 PATTERN 設(shè)為 ?,表示匹配任意一個(gè)字符。

如果參數(shù)是“*”或者“@”,對(duì)每個(gè)位置參數(shù)做上面的操作,

當(dāng)參數(shù)是以@或*為下標(biāo)的數(shù)組,對(duì)每個(gè)數(shù)組變量做如上的操作。最終結(jié)果為所有被處理過(guò)的參數(shù)的列表。

3.5.4 命令替換


命令替換允許使用命令的輸出替換命令本身。

命令替換有兩種寫(xiě)法:

$(COMMAND) 或者 `COMMAND`

命令替換按如下方式進(jìn)行:

1,執(zhí)行命令,使用命令的標(biāo)準(zhǔn)輸出替換上述的命令替換表達(dá)式。
2,如果命令輸出的尾部有跟著換行符,就將換行符刪除。
3,嵌入在命令輸出之中的換行符這時(shí)不會(huì)刪除,但可能在進(jìn)行單詞分割的時(shí)候被刪除。

'$(cat FILE)' 與 '$(< FILE)' 是相同的,但后者執(zhí)行速度更快。

使用舊式的反引號(hào) '`' 時(shí),反斜線(xiàn) '' 失去特殊意義,僅當(dāng)反斜線(xiàn)后跟 '$','`','' 時(shí),反斜線(xiàn)對(duì)其進(jìn)行轉(zhuǎn)義,否則只是普通字符。

使用 '$(COMMAND)' 時(shí),圓括號(hào)內(nèi)的所有字符不做特殊對(duì)待。

命令替換可進(jìn)行嵌套,使用 '`' 形式的命令替換時(shí),內(nèi)部的 '`' 要使用反斜線(xiàn) '' 轉(zhuǎn)義。

當(dāng)命令替換在雙引號(hào) "" 中進(jìn)行時(shí),替換的結(jié)果不再進(jìn)行單詞分割和文件名展開(kāi)。

3.5.5 算術(shù)展開(kāi)


算術(shù)展開(kāi)允許對(duì)算術(shù)表達(dá)式進(jìn)行計(jì)算,并使用計(jì)算結(jié)果替換算術(shù)展開(kāi)的整個(gè)表達(dá)式。

其語(yǔ)法為:

$(( EXPRESSION ))

對(duì)于 EXPRESSION 的處理,如同使用了雙引號(hào) '"' 將之引用,大多數(shù)的特殊字符失去特殊意義,規(guī)則參考前面專(zhuān)門(mén)的章節(jié)。這里特殊的一點(diǎn)是,EXPRESSION 中的 '"' 不做特殊對(duì)待。

EXPRESSION 中的所有 token 可能進(jìn)行:參數(shù)展開(kāi),命令替換,引用取消。

算術(shù)展開(kāi)可進(jìn)行嵌套。

算術(shù)表達(dá)式的計(jì)算規(guī)則參見(jiàn)后面的小節(jié)。

如果 EXPRESSION 是無(wú)效的,bash 打印一條消息到錯(cuò)誤輸出,替換不再進(jìn)行。

3.5.6 過(guò)程替換


如果系統(tǒng)支持命名管道(named pipes: FIFOs),或者支持命名的打開(kāi)文件的 '/dev/fd' 方法,過(guò)程替換也被支持。

其形式如下:

<(LIST) 或者 >(LIST)

過(guò)程 LIST 執(zhí)行時(shí),其輸出或輸入與 FIFO 或者 '/dev/fd' 下的文件相連。相連的文件名被當(dāng)做一個(gè)參數(shù)傳遞給當(dāng)前命令。

使用 '>(LIST)' 時(shí),對(duì)文件寫(xiě)入,相同于給 LIST 提供輸入。

使用 '<(LIST)' 時(shí),LIST的輸出寫(xiě)入文件,讀取文件,可以獲得 LIST 的輸出。

注意 '<' 或 '>' 與圓括號(hào)之間沒(méi)有空格,否則整個(gè)構(gòu)造被解釋為重定向。

過(guò)程替換可用時(shí),會(huì)與 參數(shù)和變量展開(kāi),命令替換,算術(shù)展開(kāi)同步進(jìn)行。

3.5.7 單詞分割


shell 對(duì) 參數(shù)展開(kāi),命令替換,算術(shù)展開(kāi)的結(jié)果進(jìn)行掃描。對(duì)未被雙引號(hào)引用的部分進(jìn)行單詞分割。

shell 把 '$IFS' 中的每一個(gè)字符當(dāng)做分隔符,對(duì)其他展開(kāi)生成的結(jié)果進(jìn)行單詞分割。

如果 'IFS' 沒(méi)有設(shè)置,或者其值正好是默認(rèn)值 '<space><tab><newline>',之前進(jìn)行的展開(kāi)生成的結(jié)果的開(kāi)始部分和結(jié)束部分,如果是由這三個(gè)字符組成的連續(xù)字符串,將不做處理。在中間的話(huà),會(huì)發(fā)揮單詞分隔符的作用。

如果 'IFS' 的值不是默認(rèn)值,只要空白字符在 'IFS' 之中(這時(shí)的空白符可稱(chēng)為 IFS 空白符),那么由空白字符(space 和 tab)組成的連續(xù)字符串,出現(xiàn)在展開(kāi)結(jié)果的開(kāi)始部分和結(jié)束部分時(shí),被忽略不做處理。

任何在 'IFS' 中的非空白符,與毗連的 'IFS' 空白符一起作為分隔符使用。單詞中的 'IFS' 空白符字符串也作為分隔符使用。如果 'IFS' 是空字符串,不進(jìn)行單詞分割。

顯式出現(xiàn)的空字符串("" 或者 '')將被保留。由參數(shù)值為空的參數(shù)展開(kāi)生成的未被引號(hào)引用的隱式空字符串,將被刪除。如果參數(shù)值為空的參數(shù)展開(kāi)在雙引號(hào) "" 中進(jìn)行,空字符串被保留。

如果之前沒(méi)有進(jìn)行任何展開(kāi),單詞分割也不會(huì)進(jìn)行。

3.5.8 文件名展開(kāi)


目錄:

3.8.1 模式匹配 shell 如何進(jìn)行模式匹配

完成單詞分割之后,除非設(shè)置了 '-f' 選項(xiàng)(set 命令),bash 依次掃描每個(gè)單詞,尋找 '*', '?' 和 '[',如果出現(xiàn)其中一個(gè),該單詞被認(rèn)為是一個(gè) PATTERN,并替換為一組按字典序排序的匹配的文件名。

如果沒(méi)找到匹配的文件名,而且 shell 選項(xiàng) 'nullglob' 是關(guān)閉的,該單詞保留原樣。
如果沒(méi)找到匹配的文件名,而且 shell 選項(xiàng) 'nullglob' 是開(kāi)啟的,該單詞被刪除。
如果沒(méi)找到匹配的文件名,而且 shell 選項(xiàng) 'failglob' 是開(kāi)啟的,打印一條錯(cuò)誤信息,不執(zhí)行命令。
如果 shell 選項(xiàng) 'nocaseglob' 開(kāi)啟,匹配時(shí)忽略大小寫(xiě)。

當(dāng)一個(gè) pattern 用作文件名展開(kāi)時(shí),字符 '.' 位于文件名首部的 或者'.' 跟在 '/' 之后('/.')時(shí),必須進(jìn)行顯式地匹配,除非開(kāi)啟了 'dotglob' 選項(xiàng)。

匹配文件名時(shí),字符 '/' 必須進(jìn)行顯式地匹配。除此之外,字符 '.' 不被特殊對(duì)待。

參見(jiàn) 'shopt' 命令詳細(xì)了解 'nocaseglob','nullglob','failglob' 以及 'dotglob' 選項(xiàng)。

shell 變量 'GLOBIGNORE' 可用于限制文件名的匹配。

如果設(shè)置了這個(gè)變量,每個(gè)匹配的文件名如果同時(shí)匹配 'GLOBIGNORE' 中的 pattern,這個(gè)文件名從匹配結(jié)果列表中刪除。

'GLOBIGNORE' 變量被設(shè)置且非空時(shí),文件名 '.' 和 '..' 總是被忽略。
'GLOBIGNORE' 變量設(shè)置為非空值時(shí),'dotglob' 選項(xiàng)被開(kāi)啟,所以所有其他以 '.' 開(kāi)始的文件名也會(huì)被匹配。

如果想要忽略以 '.' 開(kāi)始的文件名,可將 '.*' 設(shè)置為 'GLOBIGNORE' 變量的其中一個(gè) pattern。'GLOBIGNORE' 變量未設(shè)置時(shí),'dotglob' 選項(xiàng)被關(guān)閉。

3.5.8.1 模式匹配


pattern 中的字符,除了下面描述的特殊 pattern 字符,將匹配其自身。NUL 字符不可出現(xiàn)在 pattern 中。

'' 字符將下面的特殊字符轉(zhuǎn)義為普通字符,以匹配其自身,匹配時(shí),'' 字符自身被忽略。

希望特殊字符匹配其自身時(shí),必須將其引用(quoted)。

'*'

匹配任意字符串,包括 空字符串。

shell 選項(xiàng) 'globstar' 開(kāi)啟時(shí),'**' pattern 匹配所有文件和 0+ 個(gè)目錄及子目錄。

'**/' 只匹配目錄和子目錄。

'?'

匹配任意單個(gè)字符

'[...]'

匹配括號(hào)中任意一個(gè)字符。

一對(duì)以 '-' 分隔的字符表示 RANGE EXPRESSION(范圍表達(dá)式)。匹配這對(duì)字符之間(包括這對(duì)字符)的任意一個(gè)字符。

如果左括號(hào) '[' 后面第一個(gè)字符是 '!' 或者 '^',匹配括號(hào)內(nèi)所有字符之外的
任意一個(gè)字符。

'-' 字符放在第一個(gè)位置,或最后一個(gè)位置時(shí),可以被匹配。

']' 字符放在第一個(gè)位置,可以被匹配。

范圍表達(dá)式的排序順序由當(dāng)前 locale 語(yǔ)系 和 'LC_COLLATE' (如果已設(shè)置)的值決定。

比如,根據(jù)默認(rèn)的 C locale,'[a-dx-z]' 等效于 '[abcdxyz]'。許多其他 locale 按照字典序排序,這時(shí) '[a-dx-z]' 可能等效于 '[aBbCcDdxXyYz]'。

可通過(guò)設(shè)置 'LC_COLLATE' 或 'LC_ALL' 為 'C',強(qiáng)制使用傳統(tǒng)的 'C' 語(yǔ)系排序。

在中括號(hào)中,CHARACTER CLASSES(特定字符集)可由 '[:'CLASS':]' 指定。

POSIX 標(biāo)準(zhǔn)定義的 CLASS 包括:

alnum   alpha   ascii   blank   cntrl   digit   graph
lower   print   punct   space   upper   word    xdigit

特定字符集可匹配屬于該字符集的任意一個(gè)字符。'word' 匹配 字母,數(shù)字 和 下劃線(xiàn) '_'。

Within [ and ], an EQUIVALENCE CLASS can be specified usingthe syntax [=C=], which matches all characters with the same collation weight (as defined by the current locale) as the character C.

Within [ and ], the syntax [.SYMBOL.] matches the collating symbol SYMBOL.

如果 shell 選項(xiàng) 'extglob' 開(kāi)啟(使用 'shopt' 命令),可使用下列的擴(kuò)展 pattern。在下面的描述中, PATTERN-LIST 是由 '|' 分隔的一個(gè)
或多個(gè) pattern 組成的列表。

復(fù)合 pattern 可由下面的一個(gè)或多個(gè) pattern 組成。

'?(PATTERN-LIST)'

匹配 0 個(gè)或 1個(gè) 給出的 patterns。

'*(PATTERN-LIST)'

匹配 0 個(gè)或 多個(gè) 給出的 patterns。

'+(PATTERN-LIST)'

匹配 1 個(gè)或 多個(gè) 給出的 patterns。

'@(PATTERN-LIST)'

匹配給出的 patterns 的其中一個(gè)。

'!(PATTERN-LIST)'

匹配給出的 patterns 之外的任意字符串。

3.5.9 引用取消


前面的展開(kāi)完成之后,所有未被引用的 \,' 和 ",除了由之前的展開(kāi)生成的,都被刪除。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評(píng)論 6 545
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,795評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,943評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 64,057評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,773評(píng)論 6 414
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,106評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,282評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,793評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,507評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,741評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,929評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,325評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,661評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,482評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,702評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容