欢迎您的光临,本博所发布之文章皆为作者亲测通过,如有错误,欢迎通过各种方式指正。由于本站位于香港虚拟主机,故速度比较慢。

教程  Shell&Shell脚本基础教程——字符串

Shell 本站 184 0评论

字符串(String)就是一系列字符的组合。字符串是 Shell 编程中最常用的数据类型之一(除了数字和字符串,也没有其他类型了)。

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。


字符串举例:

str1=c.biancheng.net
str2="shell script"
str3='C语言中文网'


下面我们说一下三种形式的区别:


1) 由单引号' '包围的字符串:

任何字符都会原样输出,在其中使用变量是无效的。

字符串中不能出现单引号,即使对单引号进行转义也不行。


2) 由双引号" "包围的字符串:

如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。

字符串中可以出现双引号,只要它被转义了就行。


3) 不被引号包围的字符串

不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。

字符串中不能出现空格,否则空格后边的会作为其他变量或者字符串解析。


我们通过代码来演示一下三种形式的区别:

#!/bin/bash
n=74
str1=c.biancheng.net$n str2="shell \"script\" $n"
str3='C语言中文网 $n'
echo $str1
echo $str2
echo $str3

运行结果:

c.biancheng.net74

shell "script" 74

C语言中文网 $n


str1 中包含了$n,它被解析为变量 n 的引用。$n后边有空格,紧随空格的 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分。

str2 中包含了引号,但是被转义了(由反斜杠\开头的表示转义字符)。str2 中也包含了$n,它也被解析为变量 n 的引用。

str3 中也包含了$n,但是仅仅是作为普通字符,并没有解析为变量 n 的引用。


在做shell批处理程序时候,经常会涉及到字符串相关操作。有很多命令语句,如:awk,sed都可以做字符串各种操作。 其实shell内置一系列操作符号,可以达到类似效果,大家知道,使用内部操作符会省略启动外部程序等时间,因此速度会非常的快。


1.判断读取字符串值


表达式含义
${var}变量var的值, 与$var相同

 
${var-DEFAULT}如果var没有被声明, 那么就以$DEFAULT作为其值 *
${var:-DEFAULT}如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *

 
${var=DEFAULT}如果var没有被声明, 那么就以$DEFAULT作为其值 *
${var:=DEFAULT}如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *

 
${var+OTHER}如果var声明了, 那么其值就是$OTHER, 否则就为null字符串
${var:+OTHER}如果var被设置了, 那么其值就是$OTHER, 否则就为null字符串

 
${var?ERR_MSG}如果var没被声明, 那么就打印$ERR_MSG *
${var:?ERR_MSG}如果var没被设置, 那么就打印$ERR_MSG *

 
${!varprefix*}匹配之前所有以varprefix开头进行声明的变量
${!varprefix@}匹配之前所有以varprefix开头进行声明的变量

加入了“*”不是意思是: 当然, 如果变量var已经被设置的话, 那么其值就是$var.

 例:

[chengmo@localhost ~]$ echo ${abc-'ok'}
ok
[chengmo@localhost ~]$ echo $abc
[chengmo@localhost ~]$ echo ${abc='ok'}
ok
[chengmo@localhost ~]$ echo $abc
ok


假设abc 沒有声明“=" 还会给abc赋值。

[chengmo@localhost ~]$ var1=11;var2=12;var3=
[chengmo@localhost ~]$ echo ${!v@}            
var1 var2 var3
[chengmo@localhost ~]$ echo ${!v*}
var1 var2 var3

${!varprefix*}与${!varprefix@}相似,能够通过变量名前缀字符,搜索已经定义的变量,不管是否为空值。


2.字符串操作


表达式含义
${#string}$string的长度

 
${string:position}在$string中, 从位置$position开始提取子串
${string:position:length}在$string中, 从位置$position开始提取长度为$length的子串

 
${string#substring}从变量$string的开头, 删除最短匹配$substring的子串
${string##substring}从变量$string的开头, 删除最长匹配$substring的子串
${string%substring}从变量$string的结尾, 删除最短匹配$substring的子串
${string%%substring}从变量$string的结尾, 删除最长匹配$substring的子串

 
${string/substring/replacement}使用$replacement, 来代替第一个匹配的$substring
${string//substring/replacement}使用$replacement, 代替所有匹配的$substring
${string/#substring/replacement}如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
${string/%substring/replacement}如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
  


1)获取字符串长度

在 Shell 中获取字符串长度很简单,具体方法如下:

${#string_name}

string_name 表示字符串名字。


下面是具体的演示:

#!/bin/bash
str="http://c.biancheng.net/shell/"
echo ${#str}

运行结果:

29


string=abc12342341          #等号二边不要有空格  
echo ${#string}             #结果11  
expr length $string         #结果11  
expr "$string" : ".*"       #结果11 分号二边要有空格,这里的:根match的用法差不多


从字符串开头到子串的最大长度

expr match $string 'abc.*3' //结果9

个人觉得这个函数的用处不大,为什么要从开头开始呢。


2)查找子字符串(字符串的位置)

查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。


str="abc"  
expr index $str "a"  # 1  
expr index $str "b"  # 2  
expr index $str "x"  # 0  
expr index $str ""   # 0

这个方法让我想起来了js的indexOf,各种语言对字符串的操作方法大方向都差不多,如果有语言基础的话,学习shell会很快的。


3)Shell字符串拼接(连接、合并)

在 Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接,非常简单粗暴。请看下面的例子:

#!/bin/bash
name="Shell"
url="http://c.biancheng.net/shell/"
str1=$name$url  #中间不能有空格
str2="$name $url"  #如果被双引号包围,那么中间可以有空格
str3=$name": "$url  #中间可以出现别的字符串
str4="$name: $url"  #这样写也可以
str5="${name}Script: ${url}index.html"  #这个时候需要给变量名加上大括号
echo $str1
echo $str2
echo $str3
echo $str4
echo $str5

运行结果:

Shellhttp://c.biancheng.net/shell/

Shell http://c.biancheng.net/shell/

Shell: http://c.biancheng.net/shell/

Shell: http://c.biancheng.net/shell/

ShellScript: http://c.biancheng.net/shell/index.html


对于第 7 行代码,$name 和 $url 之间之所以不能出现空格,是因为当字符串不被任何一种引号包围时,遇到空格就认为字符串结束了,空格后边的内容会作为其他变量或者字符串解析,这一点在《Shell字符串》中已经提到。

对于第 10 行代码,加{ }是为了帮助解释器识别变量的边界,这一点在 Shell变量 一文中已经提到。


4)Shell字符串截取(详解)

Shell 截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。


a.从指定位置开始截取

这种方式需要两个参数:除了指定起始位置,还需要截取长度,才能最终确定要截取的字符串。

既然需要指定起始位置,那么就涉及到计数方向的问题,到底是从字符串左边开始计数,还是从字符串右边开始计数。答案是 Shell 同时支持两种计数方式。


从字符串左边开始计数

如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:

${string: start :length}

其中,string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),length 是要截取的长度(省略的话表示直到字符串的末尾)。

例如:

url="c.biancheng.net"
echo ${url: 2: 9}

结果为biancheng。

再如:

url="c.biancheng.net"
echo ${url: 2}  #省略 length,截取到字符串末尾

结果为biancheng.net。


从右边开始计数

如果想从字符串的右边开始计数,那么截取字符串的具体格式如下:

${string: 0-start :length}

同第 1) 种格式相比,第 2) 种格式仅仅多了0-,这是固定的写法,专门用来表示从字符串右边开始计数。


这里需要强调两点:

· 从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。

· 不管从哪边开始计数,截取方向都是从左到右。

例如:

url="c.biancheng.net"
echo ${url: 0-13: 9}

结果为biancheng。从右边数,b是第 13 个字符。

再如:

url="c.biancheng.net"
echo ${url: 0-13}  #省略 length,直接截取到字符串末尾

结果为biancheng.net。


b.从指定字符(子字符串)开始截取

这种截取方式无法指定字符串长度,只能从指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右边的所有字符,也可以截取左边的所有字符。


使用 # 号截取右边字符

使用#号可以截取指定字符(或者子字符串)右边的所有字符,具体格式如下:

${string#*chars}

其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),*是通配符的一种,表示任意长度的字符串。*chars连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取)。


请看下面的例子:

url="http://c.biancheng.net/index.html"
echo ${url#*:}

结果为//c.biancheng.net/index.html。


以下写法也可以得到同样的结果:

echo ${url#*p:}
echo ${url#*ttp:}


如果不需要忽略 chars 左边的字符,那么也可以不写*,例如:

url="http://c.biancheng.net/index.html"
echo ${url#http://}

结果为c.biancheng.net/index.html。


注意,以上写法遇到第一个匹配的字符(子字符串)就结束了。例如:

url="http://c.biancheng.net/index.html"
echo ${url#*/}

结果为/c.biancheng.net/index.html。url 字符串中有三个/,输出结果表明,Shell 遇到第一个/就匹配结束了。


如果希望直到最后一个指定字符(子字符串)再匹配结束,那么可以使用##,具体格式为:

${string##*chars}


请看下面的例子:

#!/bin/bash
url="http://c.biancheng.net/index.html"
echo ${url#*/}    #结果为 /c.biancheng.net/index.html
echo ${url##*/}   #结果为 index.html
str="---aa+++aa@@@"
echo ${str#*aa}   #结果为 +++aa@@@
echo ${str##*aa}  #结果为 @@@


使用 % 截取左边字符

使用%号可以截取指定字符(或者子字符串)左边的所有字符,具体格式如下:

${string%chars*}


请注意*的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。其他方面%和#的用法相同,这里不再赘述,仅举例说明:

#!/bin/bash
url="http://c.biancheng.net/index.html"
echo ${url%/*}  #结果为 http://c.biancheng.net
echo ${url%%/*}  #结果为 http:
str="---aa+++aa@@@"
echo ${str%aa*}  #结果为 ---aa+++
echo ${str%%aa*}  #结果为 ---


最后,我们对以上 8 种方法格式做一个汇总,请看下表:

格式说明
${string: start :length}从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
${string: start}从 string 字符串的左边第 start 个字符开始截取,直到最后。
${string: 0-start :length}从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
${string: 0-start}从 string 字符串的右边第 start 个字符开始截取,直到最后。
${string#*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string##*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string%*chars}从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string%%*chars}从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。


5)匹配显示内容

//例1中也有match和这里的match不同,上面显示的是匹配字符的长度,而下面的是匹配的内容    

expr match $string '\([a-c]*[0-9]*\)'  //abc12342341    
expr $string : '\([a-c]*[0-9]\)'       //abc1    
expr $string : '.*\([0-9][0-9][0-9]\)' //341 显示括号中匹配的内容

这里括号的用法,是不是根其他的括号用法有相似之处呢


6)截取不匹配的内容

string=abc12342341          #等号二边不要有空格  
echo ${string#a*3}     //42341  从$string左边开始,去掉最短匹配子串    
echo ${string#c*3}     //abc12342341  这样什么也没有匹配到    
echo ${string#*c1*3}   //42341  从$string左边开始,去掉最短匹配子串    
echo ${string##a*3}    //41     从$string左边开始,去掉最长匹配子串    
echo ${string%3*1}     //abc12342  从$string右边开始,去掉最短匹配子串    
echo ${string%%3*1}    //abc12     从$string右边开始,去掉最长匹配子串
str="abbc,def,ghi,abcjkl"  
echo ${str#a*c}     # 输出,def,ghi,abcjkl  一个井号(#) 表示从左边截取掉最短的匹配 (这里把abbc字串去掉)  
echo ${str##a*c}    # 输出jkl,             两个井号(##) 表示从左边截取掉最长的匹配 (这里把abbc,def,ghi,abc字串去掉)  
echo ${str#"a*c"}   # 输出abbc,def,ghi,abcjkl 因为str中没有"a*c"子串  
echo ${str##"a*c"}  # 输出abbc,def,ghi,abcjkl 同理  
echo ${str#*a*c*}   # 空  
echo ${str##*a*c*}  # 空  
echo ${str#d*f)     # 输出abbc,def,ghi,abcjkl,   
echo ${str#*d*f}    # 输出,ghi,abcjkl     
  
echo ${str%a*l}     # abbc,def,ghi  一个百分号(%)表示从右边截取最短的匹配   
echo ${str%%b*l}    # a             两个百分号表示(%%)表示从右边截取最长的匹配  
echo ${str%a*c}     # abbc,def,ghi,abcjkl

 

这里要注意,必须从字符串的第一个字符开始,或者从最后一个开始,可以这样记忆, 井号(#)通常用于表示一个数字,它是放在前面的;百分号(%)卸载数字的后面; 或者这样记忆,在键盘布局中,井号(#)总是位于百分号(%)的左边(即前面)  。


7)匹配并且替换

string=abc12342341 
echo ${string/23/bb}   //abc1bb42341  替换一次    
echo ${string//23/bb}  //abc1bb4bb41  双斜杠替换所有匹配    
echo ${string/#abc/bb} //bb12342341   #以什么开头来匹配,根php中的^有点像    
echo ${string/%41/bb}  //abc123423bb  %以什么结尾来匹配,根php中的$有点像   
 
str="apple, tree, apple tree"  
echo ${str/apple/APPLE}   # 替换第一次出现的apple  
echo ${str//apple/APPLE}  # 替换所有apple  
  
echo ${str/#apple/APPLE}  # 如果字符串str以apple开头,则用APPLE替换它  
echo ${str/%apple/APPLE}  # 如果字符串str以apple结尾,则用APPLE替换它  
 
$ test='c:/windows/boot.ini'  
$ echo ${test/\//\\}  
c:\windows/boot.ini  
$ echo ${test//\//\\}  
c:\windows\boot.ini

  

#${变量/查找/替换值} 一个“/”表示替换第一个,”//”表示替换所有,当查找中出现了:”/”请加转义符”\/”表示。  


8)比较

[[ "a.txt" == a* ]]        # 逻辑真 (pattern matching)  
[[ "a.txt" =~ .*\.txt ]]   # 逻辑真 (regex matching)  
[[ "abc" == "abc" ]]       # 逻辑真 (string comparision)   
[[ "11" < "2" ]]           # 逻辑真 (string comparision), 按ascii值比较


9)连接

s1="hello"  
s2="world"  
echo ${s1}${s2}   # 当然这样写 $s1$s2 也行,但最好加上大括号

 

10)字符串删除

$ test='c:/windows/boot.ini'  
$ echo ${test#/}  
c:/windows/boot.ini  
$ echo ${test#*/}  
windows/boot.ini  
$ echo ${test##*/}  
boot.ini  
  
$ echo ${test%/*} 
c:/windows 
$ echo ${test%%/*}

 

#${变量名#substring正则表达式}从字符串开头开始配备substring,删除匹配上的表达式。 

#${变量名%substring正则表达式}从字符串结尾开始配备substring,删除匹配上的表达式。 

#注意:${test##*/},${test%/*} 分别是得到文件名,或者目录地址最简单方法。   


3.Shell的替换


如果表达式中包含特殊字符,Shell 将会进行替换。例如,在双引号中使用变量就是一种替换,转义字符也是一种替换。


举个例子:

#!/bin/bash
a=10
echo -e "Value of a is $a \n"

运行结果:

Value of a is 10

这里 -e 表示对转义字符进行替换。如果不使用 -e 选项,将会原样输出:

Value of a is 10\n


下面的转义字符都可以用在 echo 中:

111.png

使用 echo 命令的 –E 选项禁止转义,默认也是不转义的; 使用 –n 选项可以禁止插入换行符;

使用 echo 命令的 –e 选项可以对转义字符进行替换。


另外,注意,经过我的实验,得到:

echo "\\"        #得到 \
echo -e "\\"   #得到  \
echo "\\\\"        #得到 \\
echo -e "\\"       #得到  \


命令替换:

它的意思就是说我们把一个命令的输出赋值给一个变量,方法为把命令用反引号(在Esc下方)引起来.  比如:

directory=`pwd`
echo $directory


变量替换:

可以根据变量的状态(是否为空、是否定义等)来改变它的值

222.png


参考网址:

https://www.cnblogs.com/gaochsh/p/6901809.html 

http://c.biancheng.net/view/821.html 


转载请注明: ITTXX.CN--分享互联网 » Shell&Shell脚本基础教程——字符串

最后更新:2018-12-20 18:17:09

赞 (3) or 分享 ()
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽