字符串(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 中:
使用 echo 命令的 –E 选项禁止转义,默认也是不转义的; 使用 –n 选项可以禁止插入换行符;
使用 echo 命令的 –e 选项可以对转义字符进行替换。
另外,注意,经过我的实验,得到:
echo "\\" #得到 \ echo -e "\\" #得到 \ echo "\\\\" #得到 \\ echo -e "\\" #得到 \
命令替换:
它的意思就是说我们把一个命令的输出赋值给一个变量,方法为把命令用反引号(在Esc下方)引起来. 比如:
directory=`pwd` echo $directory
变量替换:
可以根据变量的状态(是否为空、是否定义等)来改变它的值
参考网址:
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