Shell中截取字符串的用法小結


 

在日常運維工作中,經常會碰到需要在一個字符串中截取我們需要的某些字符的需求,之前介紹了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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM