简介
? ? 字符串是由一个或多个字符组成的数据类型。在编程中,字符串常用于存储和处理文本数据,可以使用单引号(’ ')或双引号(" ")括起来。
??????
目录
????????
在学习处理字符串方法之前,需要了解一些基本知识。比如我们平时在写代码时,一般不区分单引号、双引号,但在 shell 中,单引号和双引号在解释上有一些区别,先来看一个例子:
使用 echo 分别使用单引号和双引号输出字符串,这里看起来是一样的。
????????
我们来看下一个例子,输出变量
这时可以发现使用单引号,里面是什么字符就输出什么字符;使用双引号则可以进行变量替换。所以两种引号有这么一些区分:
- 单引号不会解释特殊符号,会直接按字面输出;
- 双引号可以解释特殊符号,包括:变量${ }、命令$( )、命令` ` 等。
总结:如果需要输出带有特殊字符的纯文本,使用单引号最佳;如果需要输出某些变量时,使用双引号最佳。
????????
在了解了单引号和双引号的区别后,那么下一个问题又来了,引号中怎么输出引号呢?这里列举了几种方式,懂得伙伴直接跳过。
????????
【案例一】单引号中输出单引号(目标 输出?id: 'a001' )
按我们平时思维,在引号中在放一个引号那么就可以输出,我们先来试试
echo 'id: 'a001' '
但是在 shell 的单引号字符串中,单引号字符被视为特殊字符,用于将字符串中的内容标记为一个整体。所以这种方式是不可行的(下图不符合预期)
在单引号字符串中使用转义字符 \ 来表示单引号字符本身,即 \' 表示一个单引号字符。所以正确的使用方法是?'\'' ,来看一下例子
echo 'id: '\''a001'\'' '
符合预期
????????
【案例二】单引号中输出双引号(目标 输出?id: "a001" )
单引号中嵌套双引号是可以正常使用的
echo 'id: "a001" '
????????
【案例三】双引号中输出单引号(目标 输出?id: 'a001' )
双引号中嵌套单引号也是正常的
echo "id: 'a001' "
????????
【案例四】双引号中输出双引号(目标 输出?id: "a001" )
与《案例一》不同的是,双引号中支持各种转义符,所以我们直接对双引号进行转义即可
echo "id: \"a001\" "
????????
【案例五】输出嵌套引号(目标 输出?id: "a001: 'a001.1: "b001" ' " )
echo "id: \"a001: 'a001.1: \"b001\" ' \" "
这条命令看起来老壳疼,实际上理解了就很简单。我们知道,在双引号中是可以使用单引号的,如果在双引号中使用双引号那么需要使用转义符 \" ,说到这里再看一眼命令就明白了。
????????
前面讲了不同引号的区别和引号中包含引号,这其实也是与赋值给变量有关系的。比如给变量赋值另一个变量的结果(引号的方式是一样的)
v1="AAA"
v2="BBB ${v1}"
????????
给变量赋值一个命令的执行结果
v1="AAA $(ls)"
如果 v1 已经赋值,删除当前路径下的某个文件,v1 的值也不会发生变化
????????
变量的长度也是通过 ${#变量} 获取(空格也算一个字符)
?????????
我们平时定义一个变量为 v='abc',在使用这个变量时通过 $ 符号 + 变量名,2种方式:
写法一:$v
写法二:${v}
这两种方式都可以,大部分人使用第1种方法(估计是为了少写两个字符),实际上标准写法是第2种。用《写法一》举1个简单的例子来看它的缺点:
目标:输出变量 v 和字符串 123?的组合
见上图,我们使用第1种方法,没有带花括号,那么被识别为变量 v123,所以出错了。如果我们带上花括号就不会出现这种情况
????????
除了变量之外,我们在使用索引时,也是必须使用花括号的。语法如下:
${变量名:开始索引下标:次数}
shell 中的索引没有跳跃式匹配,只能指定索引下标和后面字符数。有两个匹配方法:
# 从左往右匹配前面字符
${v:1}
# 从右往左匹配后面字符,负数需要使用括号
${v:(-1)}
注意:索引是从0开始,所以第1个字符的下标是0,比如匹配下标为0的一个字符和下标为1的一个字符
v='abcdefghji'
echo ${v:0:1} # 0表示从下标0开始,1表示只匹配1个字符
echo ${v:1:1} # 前面的1表示从下标1开始,后面的1表示只匹配1个字符
字符:a b c d e f g h j i
下标:0 1 2 3 4 5 6 7 8 9
因为只能指定索引下标的开始的次数,所以总结了以下几种方法
????????
【案例一】获取第3个字符后面的全部字符
${v:2} # 第3个字符的下标为2
????????
【案例二】获取第3个字符后面的2个字符
${v:2:2} # 第3个字符的下标为2,再指定2个字符
????????
【案例三】获取最后5个字符
${v:(-5)} # -5表示后面的5个字符
${v:(-2-3)} # 两种方法是一样的
????????
【案例四】获取后面5个字符的前面2个
${v:(-5):2} # -5表示后面的5个字符,2表示从左往右前2个字符
????????
总结
虽然看起来方法很少,但实际上我们想要的基本都可以做到。比如:
读取前面3个字符:${v:0:2}
读取后面3个字符:${v:(-3)}
读取中间第3~5个字符:${v:2:3}
????????
除了字符串常见的用法外,我们来看一下这里面的一些骚操作:先来看几个符号的解释
# :从左往右匹配第一个指定的字符,删除最前面~匹配字符
##:从右往左匹配第一个指定的字符,删除最前面~匹配字符
% :从右往左匹配第一个指定的字符,删除最后面~匹配字符
%%:从左往右匹配第一个指定的字符,删除最后面~匹配字符
* : 通配符
????????
【# 例子】从左往右匹配第一个字符 / ,删除前面的值
v=/home/yt/tmp/file
${v#*/} # 删除 / 到最前面
${v#*yt} # 删除 yt 到最前面
${v#*m} # 变量中有2个m,匹配模式是从左往右,所以删除的是 /hom
这个例子对路径可能不太合适,如果是匹配文件的后缀就很好用了
v="file.txt"
${v#*.}
????????
【## 例子】从右往左匹配第一个字符 / ,删除前面的值
v=/home/yt/tmp/file
${v##*/} # 删除最后一个 / 到最前面
${v##*tmp} # 删除 tmp 到最前面
一个 # 号获取后缀只适用于只有一个文件名,如果存在多个点还是使用 ## 更合适
????????
【%?例子】从右往左匹配第一个字符 / ,删除后面的值
v=/home/yt/tmp/file
${v%/*} # 删除 / 到最后面
${v%yt*} # 删除 yt 到最后面
${v%m*} # 变量中有2个m,匹配模式是从右往左,所以删除的是 mp/file
????????
【%% 例子】从左往右匹配第一个字符 / ,删除后面的值
v=/home/yt/tmp/file
${v%%/*} # 删除最后一个 / 到最后面
${v%%yt*} # 删除 yt 到最后面
${v%%m*} # 变量中有2个m,匹配模式是从左往右,所以删除的是 me/yt/tmp/file
????????
总结
以 . 为分隔符,不显示第1列:v=192.168.20.80
- ${v#*.}? ? #168.20.80
以 / 或 . 为分割符,查询路径最后一个文件名或后缀名:v=/home/yt/tmp/file.txt
- ${v##*/}? ? # file.txt
- ${v##*.}? ? # txt
以 / 为分隔符,显示某个文件的路径:v=/home/yt/tmp/file.txt
- ${v%/*}? ? #?/home/yt/tmp
以 . 为分隔符,只显示第1列:v=192.168.20.80
- ${v%%.*}? ? #?192
????????
《目录2.2》描述了通过 # 和 % 符号指定分隔符,那么还有一些其他的符号,比如冒号
【案例一】如果不存在变量或变量为空,则返回xxx(自定义输出)
${v:-'自定义输出'}
判断变量是否为空,如果存在一个空格也不为空
????????
【案例二】如果变量不存在或为空,则指定一个默认值
${v:='默认值'}
????????
【案例三】如果变量为空则退出程序
${v:?'变量为空,退出程序'}
????????
${v^} :转换变量v首字母为大写
${v^^}:转换变量v所有字母为大写
${v,} :转换变量v首字母为小写
${v,,}:转换变量v所有字母为小写
【案例一】转换首字母为大写、全部字母为大写
????????
【案例二】转换首字母为小写、全部字母为小写
????????
${变量/旧字符/新字符}
?????????
【案例一】将变量中 b 全部替换为 i(注意:需要两个 / 符合)
${变量//b/i}
????????
【案例二】将变量中第1个 b 替换为 i(注意:使用一个 / 符号)
${变量/b/i}
????????
【案例三】将以 ab 开头的 ab 替换为 i(注意:使用 # 符号)
${变量/#ab/i}
????????
【案例四】将以 bc 结尾的 bc 替换为 i(注意:使用符号 %)
${变量/%bc/i}