Bash技巧:使用參數擴輾轉換字符串的大小寫和替換字符串

在 bash 中,一般使用 ${parameter} 表達式來獲取 parameter 變量的值,這是一種參數擴展 (parameter expansion)。
Bash 還提供了其餘形式的參數擴展,能夠對變量值作一些處理,起到操做字符串的效果。例如:正則表達式

  • ${parameter^^pattern}parameter 變量值中匹配 pattern 模式字符的小寫字母轉成大寫。
  • ${parameter,,pattern}parameter 變量值中匹配 pattern 模式字符的大寫字母轉成小寫。
  • ${parameter/pattern/string}parameter 變量值中匹配 pattern 模式的部分替換爲 string 字符串。

注意:這些表達式都不會修改 parameter 自身的變量值,它們只是基於 parameter 變量值擴展獲得新的值。
若是要保存這些值,須要賦值給具體的變量。bash

查看 man bash 的 Parameter Expansion 小節,就能看到相關說明。具體舉例說明以下。app

${parameter^^pattern} 和 ${parameter,,pattern}

查看 man bash 對 ${parameter^pattern}, ${parameter^^pattern}, ${parameter,pattern}, ${parameter,,pattern} 的說明以下:this

Case modification.
This expansion modifies the case of alphabetic characters in parameter. The pattern is expanded to produce a pattern just as in pathname expansion.

The ^ operator converts lowercase letters matching pattern to uppercase; the , operator converts matching uppercase letters to lowercase.
The ^^ and ,, expansions convert each matched character in the expanded value; the ^ and , expansions match and convert only the first character in the expanded value. code

If pattern is omitted, it is treated like a ?, which matches every character. orm

If parameter is @ or *, the case modification operation is applied to each positional parameter in turn, and the expansion is the resultant list.
If parameter is an array variable subscripted with @ or *, the case modification operation is applied to each member of the array in turn, and the expansion is the resultant list.ip

即,這四個表達式會在 parameter 變量值中匹配 pattern 模式,並對匹配的字符進行大小寫轉換:字符串

  • ^ 操做符把小寫字母轉換爲大寫,且只轉換開頭的第一個字符
  • , 操做符把大寫字母轉換爲小寫,且只轉換開頭的第一個字符
  • ^^ 操做符把小寫字母轉換爲大寫,會轉換每個匹配的字符
  • ,, 操做符把大寫字母轉換爲小寫,會轉換每個匹配的字符

這裏的 pattern 模式可使用通配符進行擴展,注意不是用正則表達式。string

注意^, 不是轉換第一個匹配到的字符,而是隻轉換 parameter 變量值的首字符。
所給的 pattern 模式必須和 parameter 變量值的首字符匹配纔會轉換,不會轉換字符串中間的字符。it

具體舉例說明以下:

$ value="This Is a Test String."
$ echo ${value^t}
This Is a Test String.
$ echo ${value^^t}
This Is a TesT STring.
$ echo ${value,T}
this Is a Test String.
$ echo ${value,,T}
this Is a test String.

能夠看到,使用 ${value^t} 不會把 value 變量值中間小寫的 t 字符換行爲大寫。
由於這個表達式只匹配和轉換 value 變量值的首字符,value 變量值並非以小寫字母 t 開頭,不作轉換。

${value^^t} 表達式會匹配 value 變量值中的每個小寫字母 t,並轉換爲大寫。
因此輸出結果裏面再也不有小寫的 t 字符。

相似的,${value,T} 表示把 value 變量值開頭的大寫 T 轉換爲小寫的 t
${value,,T} 表示把 value 變量值全部的大寫 T 轉換爲小寫的 t

若是省略 pattern 模式,則表示匹配任意字符,但並不表示會轉換全部字符,^, 操做符仍是隻轉換首字符。

以上面的 value 變量值舉例以下:

$ echo ${value^}
This Is a Test String.
$ echo ${value^^}
THIS IS A TEST STRING.
$ echo ${value,}
this Is a Test String.
$ echo ${value,,}
this is a test string.

能夠看到,${value^} 只會把 value 變量值首字符變成大寫,因爲本來就是大寫,因此輸出結果跟 value 值同樣。
${value^^} 把全部字符都轉換爲大寫。
${value,}value 變量值首字符變成小寫。
${value,,} 把全部字符都轉換爲小寫。

注意:若是要匹配多個字符,要用方括號 [] 把字符串括起來,進行 pathname expansion,纔會獲得多個可匹配的字符。
直接把 pattern 模式寫成字符串並不能匹配該字符串中的每個字符。

以上面的 value 變量值舉例以下:

$ echo ${value,TI}
This Is a Test String.
$ echo ${value,,TI}
This Is a Test String.
$ echo ${value,,[TI]}
this is a test String.
$ echo ${value,[TI]}
this Is a Test String.

能夠看到,當所給模式寫爲 TI 時,不管是使用 , 仍是 ,, ,都不能把大寫的 TI 轉換爲小寫。
${value,TI} 甚至都不能轉換開頭的 T 字符。

而寫爲 ${value,,[TI]} 就會把全部大寫的 TI 都轉換爲小寫。
[TI] 就是 pathname expansion 的一種寫法,表示匹配方括號 [] 裏面的每個字符。
基於字符匹配,不是基於字符串匹配。
寫爲 ${value,[TI]} 表示把首字符 T 或者首字符 I 轉換爲小寫,只匹配首字符。

關於 pathname expansion 的具體寫法能夠查看 man bash 的 Pathname Expansion 部分。

最多見的就是用 * 通配符匹配零個或多個任意字符,用 ? 匹配任意單個字符。
上面說明中提到,若是省略 pattern 模式,就至關於寫爲 ?
${parameter^^} 等價於 ${parameter^^?}

${parameter/pattern/string}

查看 man bash 對 ${parameter/pattern/string} 的說明以下:

Pattern substitution.
The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string.

If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter.
If pattern begins with %, it must match at the end of the expanded value of parameter.

If string is null, matches of pattern are deleted and the / following pattern may be omitted.

If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list.
If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

即,${parameter/pattern/string} 表達式能夠替換 parameter 變量值的字符串。
所給的 pattern 模式會按照文件名擴展 (pathname expansion) 的方式來擴展,而後對 parameter 變量值進行擴展。
其值中最長匹配 pattern 的部分會被替換成 string 指定的字符串。

若是 pattern 模式開始於 /,全部匹配 pattern 模式的地方都被替換成 string 字符串。
一般僅僅替換第一個匹配的地方。

若是 pattern 模式開始於 #,它必須從頭開始匹配 parameter 變量值。
若是 pattern 模式開始於 %,它必須從後往前匹配 parameter 變量值。

若是 string 字符串是空,匹配 pattern 模式的地方會被刪除,且跟在 pattern 模式以後的 / 字符能夠省略。

具體舉例說明以下:

$ value="This is a test string. This is a new test"
$ echo ${value/test/TEST}
This is a TEST string. This is a new test
$ echo ${value//test/TEST}
This is a TEST string. This is a new TEST
$ echo ${value/#test/TEST}
This is a test string. This is a new test
$ echo ${value/#This/THIS}
THIS is a test string. This is a new test
$ echo ${value/%test/TEST}
This is a test string. This is a new TEST
$ echo ${value/test}
This is a string. This is a new test
$ echo ${value//test}
This is a string. This is a new

能夠看到,在 ${value/test/TEST} 表達式中,value 變量值是要被替換的原始字符串。
中間的 test 是要被替換的模式,且只替換第一個出現的 "test" 字符串,不會替換全部的 "test" 字符串。
後面的 TEST 是替換以後的內容。
最終輸出的結果是把 value 變量值中的第一個 "test" 字符串替換成了 "TEST",第二個 "test" 字符串沒有被替換。

${value//test/TEST} 表達式的 "/test" 模式以 / 開頭,表示替換全部出現的 "test" 字符串。
輸出結果全部的 "test" 字符串都替換成了 "TEST"。

${value/#test/TEST} 表達式的 "#test" 模式以 # 開頭,表示要從 value 變量值的第一個字符開始匹配。
因爲 value 變量值不是以 "test" 開頭,因此匹配不到,並無作替換。

要使用 ${value/#This/THIS} 來把 value 變量值開頭的 "This" 替換成 "THIS"。
${value/%test/TEST} 表達式的狀況相似,要求從 value 變量值的末尾往前匹配 "test" 字符串。
這二者都是從最後一個字符往前開始匹配。

${value/test} 表達式沒有提供替換後的 string 參數,表示從 value 變量值中刪除第一個出現的 "test" 字符串。
${value//test} 表達式的 "/test" 模式以 / 開頭,表示從 value 變量值中刪除全部出現的 "test" 字符串。

上面提到 "最長匹配" 部分會被替換。
所謂的 "最長匹配" 是指被 pattern 模式括起來的最長部分。
常見於用通配符匹配多個字符造成嵌套的狀況。

具體舉例以下:

$ value="This is a |test string|new test|, check it"
$ echo ${value/|*|/NEW STRING}
This is a NEW STRING, check it
$ echo ${value/|*|}
This is a , check it

能夠看到,所給的匹配模式是 |*|。使用 * 通配符來匹配在兩個 | 之間的任意字符串。
在所給的 value 變量值裏面,"|test string|"、"|test string|new test|" 這兩種形式都匹配這個模式。
實際被替換的是最後一種,也就是最長匹配。
因爲該模式沒有以 / 開頭,只處理第一個匹配的地方,因此 "|new test|" 不會被匹配到。

即,當 pattern 模式的擴展結果是不定長的字符串時,它會有一個前綴部分、中間變長部分、後綴部分。
那麼最長匹配是從前綴部分開始匹配,一直到最後一個匹配的後綴部分爲止,而不是遇到第一個匹配的後綴部分就中止。
中間變長部分能夠包含多個前綴部分和後綴部分。

下面再舉例說明以下:

$ value="This is a test string, first check it"
$ echo ${value/t*st}
This is a check it

能夠看到,在所給的 value 變量值裏面,t*st 模式的後綴部分 "st" 匹配到了 "first" 字符串後面的 "st"。 而不是匹配到 "test" 字符串的 "st"。 最終結果取最長匹配的部分。

相關文章
相關標籤/搜索