操作字符串
--------------
Bash支持超多的字符串操作,操作的種類和數量令人驚異.但不幸的是,這些工具缺乏集中性.
一些是參數替換的子集,但是另一些則屬於UNIX的expr命令.這就導致了命令語法的不一致和
功能的重疊,當然也會引起混亂.
1、字符串長度
${#string}
expr length $string
expr "$string" : '.*'
stringZ=abcABC123ABCabc
echo ${#stringZ}
echo `expr length $stringZ`
echo `expr "$stringZ" : '.*'`
2、從字符串開始的位置匹配子串的長度
expr match "$string" '$substring' $substring是一個正則表達式
expr "$string" : '$substring' $substring是一個正則表達式
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" 'abc[A-Z]*.2'`
echo `expr "$stringZ" : 'abc[A-Z]*.2'`
3、索引
expr index $string $substring 匹配到子串的第一個字符的位置.
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12`
echo `expr index "$stringZ" 1c`
# 'c' (in #3 position) matches before '1'.
在C語言中最近的等價函數為strchr().
提取子串
${string:position}
在string中從位置$position開始提取子串.
如果$string為"*"或"@",那么將提取從位置$position開始的位置參數,[1]
${string:position:length}
在string中從位置$position開始提取$length長度的子串.
################################StartScript######################################
stringZ=abcABC123ABCabc
# 0123456789.....
# 0-based indexing.
echo ${stringZ:0} # abcABC123ABCabc
echo ${stringZ:1} # bcABC123ABCabc
echo ${stringZ:7} # 23ABCabc
echo ${stringZ:7:3} # 23A
# 3個字符長度的子串.
# 有沒有可能從字符結尾開始,反向提取子串?
echo ${stringZ:-4} # abcABC123ABCabc
# 以${parameter:-default}方式,默認是提取完整地字符串.
# 然而 . . .
echo ${stringZ:(-4)} # Cabc
echo ${stringZ: -4} # Cabc
# 現在,它可以工作了.
# 使用圓括號或者添加一個空格來轉義這個位置參數.
如果$string參數為"*"或"@",那將最大的提取從$position開始的$length個位置參數.
echo ${*:2} # Echo出第2個和后邊所有的位置參數.
echo ${@:2} # 與前邊相同.
echo ${*:2:3} # 從第2個開始,Echo出后邊3個位置參數.
expr substr $string $position $length
在string中從位置$position開始提取$length長度的子串.
stringZ=abcABC123ABCabc
# 123456789......
# 1-based indexing.
echo `expr substr $stringZ 1 2` # ab
echo `expr substr $stringZ 4 3` # ABC
expr match "$string" '\($substring\)'
從$string的開始位置提取$substring,$substring是一個正則表達式.
expr "$string" : '\($substring\)'
從$string的開始位置提取$substring,$substring是一個正則表達式.
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
echo `expr "$stringZ" : '\(.......\)'` # abcABC1
# All of the above forms give an identical result.
子串削除
${string#substring}
從$string的左邊截掉第一個匹配的$substring
${string##substring}
從$string的左邊截掉最后一個個匹配的$substring
stringZ=abcABC123ABCabc
# |----|
# |----------|
echo ${stringZ#a*C} # 123ABCabc
# 截掉'a'和'C'之間最近的匹配.
echo ${stringZ##a*C} # abc
# 截掉'a'和'C'之間最遠的匹配.
${string%substring}
從$string的右邊截掉第一個匹配的$substring
${string%%substring}
從$string的右邊截掉最后一個匹配的$substring
stringZ=abcABC123ABCabc
# ||
# |------------|
echo ${stringZ%b*c} # abcABC123ABCa
# 從$stringZ的后邊開始截掉'b'和'c'之間的最近的匹配
echo ${stringZ%%b*c} # a
# 從$stringZ的后邊開始截掉'b'和'c'之間的最遠的匹配
Example 9-11 利用修改文件名,來轉換圖片格式
################################StartScript######################################
#!/bin/bash
# cvt.sh:
# 把一個目錄下的所有MacPaint格式的圖片文件都轉換為"pbm"格式的圖片文件.
# 使用來自"netpbm"包的"macptopbm"程序,
#+ 這個程序主要是由Brian Henderson(bryanh@giraffe-data.com)來維護的.
# Netpbm是大多數Linux發行版的標准部分.
OPERATION=macptopbm
SUFFIX=pbm # 新的文件名后綴
if [ -n "$1" ]
then
directory=$1 # 如果目錄名作為第1個參數給出...
else
directory=$PWD # 否則使用當前的工作目錄.
fi
# 假設在目標目錄中的所有文件都是MacPaint格式的圖片文件,
#+ 以".mac"為文件名的后綴.
for file in $directory/* # Filename globbing.
do
filename=${file%.*c} # 去掉文件名的".mac"后綴
#+ ('.*c' matches everything
#+ ('.*c' 將匹配'.'和'c'之間的任何字符串).
$OPERATION $file > "$filename.$SUFFIX"
# 轉換為新的文件名.
rm -f $file # 轉換完畢后刪除原有的文件.
echo "$filename.$SUFFIX" # 從stdout輸出反饋.
done
exit 0
# 修改這個腳本,讓他只轉換以".mac"為后綴的文件.
################################EndScript#######################################
一個簡單的模擬getopt命令的辦法就是使用子串提取結構.
Example 9-12 模仿getopt命令
################################StartScript######################################
#!/bin/bash
# getopt-simple.sh
# Author: Chris Morgan
# 授權使用在ABS Guide中.
getopt_simple()
{
echo "getopt_simple()"
echo "Parameters are '$*'"
until [ -z "$1" ]
do
echo "Processing parameter of: '$1'"
if [ ${1:0:1} = '/' ]
then
tmp=${1:1} # 去掉開頭的'/' . . .
parameter=${tmp%%=*} # 提取名字.
value=${tmp##*=} # 提取值.
echo "Parameter: '$parameter', value: '$value'"
eval $parameter=$value
fi
shift
done
}
# 傳遞所有的選項到getopt_simple().
getopt_simple $*
echo "test is '$test'"
echo "test2 is '$test2'"
exit 0
---
sh getopt_example.sh /test=value1 /test2=value2
Parameters are '/test=value1 /test2=value2'
Processing parameter of: '/test=value1'
Parameter: 'test', value: 'value1'
Processing parameter of: '/test2=value2'
Parameter: 'test2', value: 'value2'
test is 'value1'
test2 is 'value2'
################################EndScript#######################################
子串替換
${string/substring/replacement}
使用$replacement來替換第一個匹配的$substring.
${string//substring/replacement}
使用$replacement來替換所有匹配的$substring.
1 stringZ=abcABC123ABCabc
2
3 echo ${stringZ/abc/xyz} # xyzABC123ABCabc
4 # 用'xyz'來替換第一個匹配的'abc'.
5
6 echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
7 # 用'xyz'來替換所有匹配的'abc'.
${string/#substring/replacement}
如果$substring匹配$string的開頭部分,那么就用$replacement來替換$substring.
${string/%substring/replacement}
如果$substring匹配$string的結尾部分,那么就用$replacement來替換$substring.
1 stringZ=abcABC123ABCabc
2
3 echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
4 # 用'XYZ'替換開頭的'abc'
5
6 echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
7 # 用'XYZ'替換結尾的'abc'
9.2.1 使用awk來操作字符串
~~~~~~~~~~~~~~~~~~~~~~~~~
Bash腳本也可以使用awk來操作字符串.
Example 9-13 提取字符串的一種可選的方法
################################StartScript######################################
#!/bin/bash
# substring-extraction.sh
String=23skidoo1
# 012345678 Bash
# 123456789 awk
# 注意,對於awk和Bash來說,它們使用的是不同的string索引系統:
# Bash的第一個字符是從'0'開始記錄的.
# Awk的第一個字符是從'1'開始記錄的.
echo ${String:2:4} # 位置3 (0-1-2), 4 個字符長
# skid
# awk中等價於${string:pos:length}的命令是substr(string,pos,length).
echo | awk '
{ print substr("'"${String}"'",3,4) # skid
}
'
# 使用一個空的"echo"通過管道給awk一個假的輸入,
#+ 這樣可以不用提供一個文件名.