在日常運維工作中,經常會碰到需要在一個字符串中截取我們需要的某些字符的需求,之前介紹了Shell腳本中數組的使用方法,這里介紹下基於字符串的截取的方法。在shell中截取字符串的方法有下面集中:
${var#*/}
${var##*/}
${var%/*}
${var%%/*}
${var:start:len}
${var:start}
${var:0-start:len}
${var:0-start}
可以總結為:
********************************************
# 刪除最小的匹配前綴
## 刪除最大的匹配前綴
% 刪除最小的匹配后綴
%% 刪除最大的匹配后綴
********************************************
1)獲得字符串的長度
語法:${#var}
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" length=${#str} echo "length: [${length}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] length: [37]
2)使用 # 和 ## 獲取尾部子字符串(*號在分隔符的前面,就去掉其之前的字符)
2.1) # 最小限度從前面截取word
語法:${parameter#*word} , 即截取 "第一個分隔符word及其之前的字符全部刪掉"后的字符
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #分割符為'/' substr=${str#*/} echo "substr: [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr: [/www.kevin.com/shibo/anhuigrace]
2.2)## 最大限度從前面截取word
語法:${parameter##*word},即截取 "最后一個分隔符word及其之前的字符全部刪掉"后的字符
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #分割符為'/' substr=${str##*/} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [anhuigrace]
3)使用 % 和 %% 獲取頭部子字符串 (*在分隔符的后面,就去掉其之后的字符)
3.1)% 最小限度從后面截取word
語法:${parameter%word*},即截取 "最后一個分隔符word及其之后的字符全部刪掉"后的字符
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" substr=${str%/*} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [http://www.kevin.com/shibo]
3.2)%% 最大限度從后面截取word
語法:${parameter%%*word},即截取 "第一個分隔符word及其之后的字符全部刪掉"后的字符
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" substr=${str%%/*} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [http:]
4)使用 ${var:} 模式獲取子字符串
4.1)指定從左邊第幾個字符開始以及子串中字符的個數
語法:${var:start:len}
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #其中的 0 表示左邊第一個字符開始,7 表示子字符的總個數。 substr=${str:0:7} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [http://]
4.2)從左邊第幾個字符開始一直到結束
語法:${var:7}
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #其中的7表示左邊第8個字符開始 (如果是${str:7:5},就表示從左邊第8個字符開始截取,截取5個字符) substr=${str:7} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [www.kevin.com/shibo/anhuigrace]
4.3)從右邊第幾個字符開始以及字符的個數
語法:${var:0-start:len};即${var:0-8,3} 和 ${var:2-10:3} 和 ${var:5:13:3} 是一樣的,即從右邊第8個開始截取,截取3個字符。 即8-0=10-2=13-5=8
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #其中的 0-23 表示右邊算起第23個字符開始,5 表示字符的個數 substr=${str:0-23:5} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [in.co]
4.4)從右邊第幾個字符開始一直到結束
語法:${var:0-start}
[root@kevin~]# cat test.sh #!/bin/bash str="http://www.kevin.com/shibo/anhuigrace" echo "string: [${str}]" #其中的 0-6 表示右邊算起第6個字符開始 substr=${str:0-6} echo "substr : [${substr}]" 執行結果為: [root@kevin~]# sh test.sh string: [http://www.kevin.com/shibo/anhuigrace] substr : [igrace]
#################### $( ) 、${ }、$(( ))的用法區別 ####################
一、$( ) 與 ` ` (反引號) ######################################################################################################################## 在Shell 中,$( ) 與 ` ` (反引號) 都是用來做命令替換用的。 命令替換:就是完成()或反引號里的命令行,然后將其結果替換出來,再重組命令行。 例如: [root@ss-server ~]# echo "this is $(date +%Y-%m-%d)" this is 2020-01-08 [root@ss-server ~]# echo "this is `date +%Y-%m-%d`" this is 2020-01-08 ###### 使用 $( ) 的理由 ###### 1)` ` 反引號很容易與 ' ' 單引號搞混亂; 2)在多層次的復合替換中,` `反引號須要額外的跳脫( \` )處理,而 $( ) 則比較直觀; 比如命令:command1 `command2 `command3` ` 原本的意圖: 是要在 command2 `command3` 中先將 command3 提換出來給 command 2 處理,然后再將結果傳給 command1 `command2 …` 來處理。 然而,真正的結果: 在命令行中卻是分成了 `command2 ` 與 ''兩段。 小示例: 使用多層次的``反引號 [root@ss-server ~]# echo `echo `date +%Y-%m-%d`` date +%Y-%m-%d 換成 $( ) 就沒問題了,做多少層的替換都沒問題! [root@ss-server ~]# echo $(echo $(date +%Y-%m-%d)) 2020-01-08 ###### $( ) 的不足 ###### $( ) 並不見的每一種 shell類型都能使用,如果使用 bash2 的話,肯定沒問題。 二、${ } 用來作變量替換 ######################################################################################################################## 一般情況下,$var 與 ${var} 並沒有什么不一樣。但是用 ${ } 會比較精確的界定變量名稱的范圍! 如下: [root@ss-server ~]# a=b [root@ss-server ~]# echo $ab [root@ss-server ~]# echo ${a}b bb 原本是打算先將 $a 的結果替換出來,然后再補一個 b 字母於其后, 但在命令行上,真正的結果卻是只會提換變量名稱為 ab 的值出來,結果沒有ab的變量,結果就為空了! 若使用 ${ } 就沒問題。 再注意區分下面的情況:即設置變量,以 = 左邊的為變量名,如以右邊為變量名則無效! [root@ss-server ~]# a=b [root@ss-server ~]# echo ${b} [root@ss-server ~]# echo ${a} b [root@ss-server ~]# echo $a b b b [root@ss-server ~]# echo ${a}${b} b [root@ss-server ~]# echo ${a}${a} bb [root@ss-server ~]# echo ${b}${b} [root@ss-server ~]# ###################################################################### 下面開始介紹下${ } 的一些高階功能 先定義一個變量,下面示例都是以給變量做說明: [root@ss-server ~]# file=/dir1/dir2/dir3/my.file.txt 1)可以用 ${ } 分別替換獲得不同的值 --------------------------- 使用#和%進行截取字符串的方法在文章上面已經詳細介紹了,這里就不做過多說明了。 ${file#*/}: 表示刪除掉第一條 / 及其左邊的字符串,即結果為:dir1/dir2/dir3/my.file.txt ${file##*/}: 表示刪除掉最后一條 / 及其左邊的字符串,即結果為:my.file.txt ${file#*.}: 表示刪除掉第一個 . 及其左邊的字符串,即結果為:file.txt ${file##*.}: 表示刪除掉最后一個 . 及其左邊的字符串,即結果為:txt ${file%/*}: 表示刪除掉最后一條 / 及其右邊的字符串,即結果為:/dir1/dir2/dir3 ${file%%/*}: 表示刪除掉第一條 / 及其右邊的字符串,即結果為:(空值) ${file%.*}: 表示刪除掉最后一個 . 及其右邊的字符串,即結果為:/dir1/dir2/dir3/my.file ${file%%.*}: 表示刪除掉第一個 . 及其右邊的字符串,即結果為:/dir1/dir2/dir3/my 關於上面使用 # 和 % 的記憶方法為: # 是刪除掉指定字符串左邊的! % 是刪除掉指定字符串右邊的! 單一符號是最小匹配﹔兩個符號是最大匹配 #*str 是刪除掉第一個str及其左邊的內容; ##*str 是刪除掉最后一個str及其左邊的內容; %str* 是刪除掉最后一個str及其右邊的內容;%%str* 是刪除掉第一個str及其右邊的內容! 下面的截圖字符串的方法在文章上面已經詳細介紹了,這里就不做過多說明了。 ${file:0:5}: 表示提取最左邊的5個字節,即結果為:/dir1 ${file:5:10}: 表示提取第5個字節右邊的連續10個字節,即結果為:/dir2/dir3 如下腳本示例: [root@bzacbsc01ap2001 ~]# hostname bzacbsc01ap2001 主機名中第3到第6字符是本機的業務模塊名稱,也就是cbs。下面腳本中的表示從a字符串左邊的第4個字符開始截取,截取3個字符(即3:3) [root@bzacbsc01ap2001 ~]# cat test.sh #!/bin/bash a=$(hostname) b=${a:3:3} APP=$(echo ${b}) echo "本機tomcat的安裝目錄為: /opt/${APP}/tomcat" 執行結果為: [root@bzacbsc01ap2001 ~]# sh test.sh 本機tomcat的安裝目錄為: /opt/cbs/tomcat 2)可以使用 ${ } 對變量值里的字符串作替換 --------------------------- ${file/dir/path}: 表示將第一個 dir 提換為 path,即結果為:/path1/dir2/dir3/my.file.txt ${file//dir/path}:表示將全部 dir 提換為 path,即結果為:/path1/path2/path3/my.file.txt 如下示例: [root@ss-server ~]# Test_Name=kevin/bo/AnHui [root@ss-server ~]# Test_Path=${Test_Name////.} #使用//將變量中所有的/替換為. [root@ss-server ~]# echo ${Test_Path} kevin.bo.AnHui [root@ss-server ~]# Test_Path=${Test_Path/.//} #使用/將變量中第一個.替換為/ [root@ss-server ~]# echo ${Test_Path} kevin/bo.AnHui [root@ss-server ~]# Test_Path=$(echo $Test_Path | tr '[A-Z]' '[a-z]') [root@ss-server ~]# echo ${Test_Path} kevin/bo.anhui 可以在shell腳本中進行變量的多次替換,如下: [root@ss-server ~]# vim test.sh #!/bin/bash MODULE_NAME=$1 ......... # image信息 IMAGE_PATH=${MODULE_NAME////.} IMAGE_PATH=${IMAGE_PATH/.//} IMAGE_PATH="$IMAGE_PATH.$BRANCH.$SERVICE_NAME" IMAGE_PATH=$(echo $IMAGE_PATH | tr '[A-Z]' '[a-z]') TAG=${REVISION:0:7} ......... 3)使用 ${ } 還可以針對不同的變量狀態賦值 (沒設定、空值、非空值) --------------------------- ${file-my.file.txt}: 表示假如 $file 沒有設定,則使用 my.file.txt 作傳回值。(空值及非空值時不作處理) ${file:-my.file.txt}: 表示假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作處理) ${file+my.file.txt}: 表示假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作處理) ${file:+my.file.txt}: 表示假如 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作處理) ${file=my.file.txt}: 表示假如 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作處理) ${file:=my.file.txt}: 表示假如 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (非空值時不作處理) ${file?my.file.txt}: 表示假如 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作處理) ${file:?my.file.txt}: 表示假如 $file 沒設定或為空值,則將 my.file.txt 輸出至 STDERR。 (非空值時不作處理) ${1:-NULL} 表示是當$1為空時,自動將NULL替換成$1所要帶入的變量值。 ${2:-NULL} 表示是當$2為空時,自動將NULL替換成$2所要帶入的變量值。 例如: [root@ss-server ~]# kevin=123 [root@ss-server ~]# echo ${kevin+anhui} anhui [root@ss-server ~]# echo ${haha:=null} #haha變量沒有設定,則使用=后面的null作為傳回值 null 也可以在shell腳本中進行變量的狀態賦值 [root@ss-server ~]# vim test.sh #!/bin/bash ......... AFS_ENV=${AFS_ENV:=null} AFS_APPID=${AFS_APPID:=null} AFS_CLUSTER=${AFS_CLUSTER:=null} AFS_JARNAME=${AFS_JARNAME:=null} ......... 對於上面的理解,在於一定要分清楚 unset 與 null 及 non-null 這三種賦值狀態。 一般而言, : 與 null 有關, 若不帶 : 的話, null 不受影響, 若帶 : 則連 null 也受影響! [root@ss-server ~]# kevin=123 [root@ss-server ~]# echo ${kevin:+anhui} anhui [root@ss-server ~]# kevin= [root@ss-server ~]# echo ${kevin:+anhui} [root@ss-server ~]# unset kevin [root@ss-server ~]# echo ${kevin:+anhui} [root@ss-server ~]# 使用${#var}可以計算出變量的長度 [root@ss-server ~]# echo ${file} /dir1/dir2/dir3/my.file.txt [root@ss-server ~]# echo ${#file} 27 三、bash的組數(array)處理方法 ######################################################################################################################## 一般而言,A="be sh se cho" 這樣的變量只是將 $A 替換為一個單一的字符串, 但是改為 A=(be sh se cho) ,則是將 $A 定義為組數,所以說數組定義需要使用()括號!! 關於數組的使用,之前已經在 https://www.cnblogs.com/kevingrace/p/5761975.html 這篇文章中詳細介紹了,這里簡略說下: 組數常用的幾個替換方法: ${A[@]} 或 ${A[*]} 表示獲得全部組數,即得到be sh se cho 。 ${A[0]} 表示獲得數組中的第1個組數。同理,${A[1]} 獲得的是第2個組數。 ${#A[@]} 或 ${#A[*]} 表示獲得全部組數數量。 ${#A[0]} 表示獲得第一個組數的長度,即be的長度,為2; 同理,${#A[3]} 表示獲得第四個組數的長度,即cho的長度,為3; A[1]=haha 表示將第2個組數重新定義為haha; 同理,A[3]=heihei 表示將第4個組數重新定義為heihei; 四、$(( )) 用途:用來作整數運算 ######################################################################################################################## 在 bash 中,$(( )) 的整數運算符號大致有這些: + - * / 分別表示為 "加、減、乘、除"。 % 表示余數運算 & | ^ ! 分別表示分別為 "AND、OR、XOR、NOT" 運算。 例如: [root@ss-server ~]# a=6;b=7;c=8 [root@ss-server ~]# echo $(( a+b*c )) 62 [root@ss-server ~]# echo $(( (a+b+3)/c )) 2 [root@ss-server ~]# echo $(( (a*b)%c)) 2 使用$[]、let、$(()) 都可以作為整數運算,效果是一樣的! [root@ss-server ~]# echo $((4*9)) 36 [root@ss-server ~]# echo $[4*9] 36 [root@ss-server ~]# let a=4*9 [root@ss-server ~]# echo $a 36 [root@ss-server ~]# let "a=4*9" [root@ss-server ~]# echo $a 36 [root@ss-server ~]# let a="3+5" [root@ss-server ~]# echo $a 8 [root@ss-server ~]# a=18 [root@ss-server ~]# let a++ [root@ss-server ~]# echo $a 19 事實上,單純用 (( )) 也可重定義變量值。 (( )) 這組符號的作用與 let 指令相似,用在算數運算上,是 bash 的內建功能。所以,在執行效率上會比使用 let指令要好許多。 [root@ss-server ~]# a=10; ((a++)) [root@ss-server ~]# echo ${a} 11 [root@ss-server ~]# cat test.sh #!/bin/bash (( a = 10 )) echo -e "inital value, a = $a\n" (( a++)) echo "after a++, a = $a" [root@ss-server ~]# sh test.sh inital value, a = 10 after a++, a = 11 更多內容,可參考另一篇文章的總結: https://www.cnblogs.com/kevingrace/p/5896386.html