You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
👆 以上 ${arr[@]} 和 ${arr[*]} 都输出数组所有成员 a b c。因此,利用这两个特殊索引,可配合 for 循环来遍历数组。
foritemin"${arr[@]}";doecho$itemdone
5.6 ${arr[@]} 和 ${arr[*]} 细节区别
其差异,主要体现在 for 循环上。
示例一:
arr=('aa 00''bb 11''cc 22')
echo'use @, with double quote:'foritemin"${arr[@]}";doecho"--> item: $item"doneecho'use @, without double quote:'foritemin${arr[@]};doecho"--> item: $item"done
👆 都是使用了 @,区别在于 ${arr[@]} 外层是否使用了「双引号」。bash 输出如下:👇
use @, with double quote:
--> item: aa 00
--> item: bb 11
--> item: cc 22
use @, without double quote:
--> item: aa
--> item: 00
--> item: bb
--> item: 11
--> item: cc
--> item: 22
arr=('aa 00''bb 11''cc 22')
echo'use *, with double quote:'foritemin"${arr[*]}";doecho"--> item: $item"doneecho'use *, without double quote:'foritemin${arr[*]};doecho"--> item: $item"done
👆 都是使用了 *,区别在于 ${arr[*]} 外层是否使用了「双引号」。bash 输出如下:👇
use *, with double quote:
--> item: aa 00 bb 11 cc 22
use *, without double quote:
--> item: aa
--> item: 00
--> item: bb
--> item: 11
--> item: cc
--> item: 22
一、前言
Shell 脚本语言是一门弱类型语言。实际上,它并没有数据类型的概念,无论你输入的是字符串还是数字,都是按照字符串类型来存储的。
举个例子:
👆 以上示例,Shell 认为
1+2
是字符串,而不是算术运算之后将结果再赋值给变量sum
。如果你要进行算术运算,可以用
let
命令或expr
命令。👆 根据
let
命令,Shell 确定了你想要的是算术运算,因此就能得到3
。如果非要划分的话,可以有:「字符串」、「布尔值」、「整数」和「数组」。
二、字符串
在 Shell 中,最常见的就是字符串类型了。注意几点:
关于引号的用法,推荐看下 👉 Google Shell Style Guide - quoting。
举个例子:
👆 以上示例语法上是允许的,👇 以下则是错误示例。
2.1 获取字符串长度
语法为
${#变量名}
,且{}
是必须的。2.2 截取子串
语法为
${变量名:起始位置:截取长度}
,注意起始位置从0
开始计算。以上操作,不会改变原字符串,类似 JavaScript 的
Array.prototype.substr()
方法。比如
${str:6:5}
,在变量str
中截取第6
位(包含)开始,长度为5
的子串。👆 以上
${str:6:5}
可以替换为${str: -6:-1}
,表示截取变量str
中倒数第6
位(包含)开始,到倒数第1
个之前的子串。2.3 字符串搜索与替换
Shell 提供了多种搜索、替换的方法。
具体看这一篇:Bash 字符串操作。请注意,替换方法只有贪婪匹配模式。
2.4 大小写转换
利用
tr
(transform)命令,可实现大小写转换。三、布尔值
定义布尔值跟字符串一样 👇
注意条件判断即可,举个例子:
👆 以上示例,只有变量
bool
的值为false
,才会进入then
语句输出Done
。就算是bool
未定义、或变量被删除了、或者bool
的值为空字符,都不会进入then
语句。因此,布尔值正确的判断方式,应使用
test
命令,或使用test
的简写语法[ ]
或[[ ]]
。比如:👆 以上判断方式,只有当变量
bool
的值为true
或false
时,才会命中条件。四、整数
4.1 算术运算
在 Shell 有两种语法可以进行算术运算。
其中
(( ... ))
内部的空白符会被忽略,因此((1+1))
和(( 1 + 1 ))
是一样的。若要获取运算结果,需在前面加上
$
,即$(( ... ))
,使其变成算术表达式,返回运算结果。(( ... ))
支持这些运算操作:加减乘除、取余(%
)、指数(**
)、自增(++
)、自减(--
)。注意点:
4.2 expr 命令
expr
是一个表达式计算工具。支持:+
-
\*
/
%
注意,这里乘法运算
\*
要加\
转义,否则 Shell 解析特殊符号。还有,非整数参与运算会报错哦!4.3 let 命令
let
命令用于将算术运算的结果,赋予一个变量。👆 以上示例,使得变量
sum
等于1+2
的运算结果。注意,sum=1+2
里面不能有空格。4.4 小数运算
以上
(( ... ))
和expr
命令均不支持小数运算,如果想进行小数运算,可以借助bc
计算器或者awk
命令。👆 其中
scale=4
表示保留四位小数。4.5 逻辑运算
(( ... ))
也提供了逻辑运算:<
小于>
大于<=
小于或相等>=
大于或相等==
相等!=
不相等&&
逻辑与||
逻辑或!
逻辑否expr1 ? expr2 : expr3
三元条件运算符。若表达式expr1
的计算结果为非零值(算术真),则执行表达式expr2
,否则执行表达式expr3
。五、数组
在 Shell 中,可以用数组来存放多个值,数组元素之间通过「空格」隔开。只支持一维数组,不支持多维数组。
5.1 数组起始索引
现代高级编程语言中,它们的数组起始索引多数都是
0
。但在 Shell 编程语言中,不同的 Shell 解析器其数组起始索引(下标)可能是不同的。比如 bash 的起始索引
0
,zsh 的起始索引是1
。👇 摘自 StackExchange:
这样看,起始索引为
1
的 Shell 解析器占多数。对于习惯了从0
开始的我来说,这一点是有的难以接受的。关于数组起始索引,有兴趣的可看:CITATION NEEDED。👆 以上示例,使用 bash 去解析是没问题的。但用 zsh 解析时,就会报错:
assignment to invalid subscript range
。因为 zsh 的起始索引是1
开始的,所以索引0
是一个不合法的下标。5.2 创建数组
可使用以下几种方式来创建数组:
注意几点:
[2]=val3
形式不允许有空格。前面提到,不同类型的 Shell 的起始索引可能是不一样的,因此以上采用
[0]
、[1]
、[2]
等方式设置指定项的值,其表示的第几项元素可能是不相同的。还可以这样 👇
5.3 读取数组长度
前面介绍过,读取字符串长度的语法为
${#变量名}
,数组也是类似的。但要借助数组的特殊索引
@
和*
,将数组扩展成列表,然后再次使用#
获取数组的长度。语法有以下两种:👆 以上结果均输出
3
。如果是读取数组某项的长度,则使用
${#数组变量名[下标]}
的形式。比如:👆以上输出
3
,它读取的是索引为10
的元素的值的长度。5.4 读取数组单个成员
其语法为
${数组变量[下标]}
,比如:👆 基于起始索引的问题,
${arr[1]}
输出值可能是a
,也可能是b
。注意,里面的
{}
不能省略,否则$arr[1]
在 bash 里输出位a[1]
,相当于$arr
的值与字符串[1]
连接,因此结果是a[1]
。注意以下语法:
👆 在 zsh 中,可以输出数组所有项,即
a b c
,在 bash 则是输出数组第一项,即a
。若想在各种 Shell 环境下统一,最合理的做法是什么呢?使用类似截取字符串子串的语法:
${array[@]:offset:length}
其中
array[@]
表示所有元素,offset
表示偏移量(总是从0
开始),length
表示截取长度。这种语法在不同 Shell 环境下总能获得一致行为。因此${arr[@]:0:1}
总能正确地取到数组的第一项。5.5 读取数组所有成员
利用数组的特殊索引
@
和*
,它们返回数组的所有成员。👆 以上
${arr[@]}
和${arr[*]}
都输出数组所有成员a b c
。因此,利用这两个特殊索引,可配合for
循环来遍历数组。5.6
${arr[@]}
和${arr[*]}
细节区别其差异,主要体现在
for
循环上。示例一:
👆 都是使用了
@
,区别在于${arr[@]}
外层是否使用了「双引号」。bash 输出如下:👇这里用高级语言来类比:首先,原数组是
['aa 00', 'bb 11', 'cc 22']
。如果带双引号"${arr[@]}"
,遍历的是原数组。如果不带双引号${arr[@]}
,相当于内部隐式地做了一次「扁平化」操作,使其变成['aa', '00', 'bb', '11', 'cc', '22']
形式,最终遍历的是扁平化后的产物。示例二:
👆 都是使用了
*
,区别在于${arr[*]}
外层是否使用了「双引号」。bash 输出如下:👇从结果上看,
"${arr[*]}"
把数组所有项当成了一个整体,遍历时只有一项。而不带双引号时,${arr[*]}
与${arr[@]}
行为一致,都把原数组扁平化了。对于类似
arr=(a b c)
的数组(即数组每一项不包含空白符), 循环中"${arr[@]}"
、${arr[@]}
、${arr[*]}
行为都是一致的,而"${arr[*]}"
同样是把原数组所有项当做一个整体了。提一下,上述示例输出结果均在 bash 下执行。但在 zsh 环境下,这三种
"${arr[@]}"
、${arr[@]}
、${arr[*]}
形式,都能「正确」遍历原数组,不会扁平化。5.7 截取数组
其实前面已经提到过了,其语法就是:
${array[@]:offset:length}
。比如:其中
offset
为偏移量(总是从0
开始),length
表示截取长度。它不会改变原数组,类似于 JavaScript 的Array.prototype.slice()
方法。${array[@]:offset:1}
也是获取数组中某项最兼容的写法。若
length
省略,截取从offset
开始到结尾的数组项。其中offset
和length
也支持负值,类似字符串截取,这里不再展开。5.8 追加数组成员
数组末尾追加成员,可以使用
+=
赋值操作符,会自动把值最佳到数字末尾。注意
+=
前后不能有空格,若追加多项元素,则使用空格隔开。如果知道了数组下标,也可以使用
arr[index]=xxx
形式添加。但注意若index
位置已有元素,则会产生覆盖效果。5.9 删除数组成员
清空数组,应使用
unset
语法。比如:对于
arr=''
这种形式,在 zsh 上可以起到清空数组的作用,而 bash 上是对数组第一项赋值为空字符串而已。如是删除某项,可以这样:
未完待续...
The text was updated successfully, but these errors were encountered: