shell脚本编程----数据
1、shell变量
脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。
在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。这意味着,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。例如在C语言或者 C++ 中,变量分为整数、小数、字符串、布尔等多种类型。
1.1、定义变量
Shell 支持以下三种定义变量的方式: variable name=value variable name='value' variable name="value"
Shell 变量的命名规范和大部分编程语言都一样:
变量名由数字、字母、下划线组成;
必须以字母或者下划线开头;
不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
注意,赋值号=的周围不能有空格,这可能和你熟悉的大部分编程语言都不一样。
variable 是变量名,value 是赋给变量的值。如果 value 不包含任何空白符(例如空格、Tab 缩进等),那么可以不使用引号;如果 value 包含了空白符,那么就必须使用引号包围起来。
使用单引号和使用双引号也是有区别的:单引号包围会将引号内部的内容当字符串文本处理,不会解析命令和变量;双引号包围时会解析里面的命令和变量。
如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。
1.2、使用变量
使用一个定义过的变量,只要在变量名前面加美元符号$即可,如:
#!/bin/bash
#定义变量
data_1=888
data_2='data_2=${data_1}'
data_3="data_3=${data_1}" #变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,所以一般最好加上
readonly data_4=123 #readonly用来声明变量为只读变量
#使用变量
echo "data_1="${data_1} #echo命令用来输出的,使用变量是前面加$
echo ${data_2}
echo ${data_3}
echo "data_4="${data_4}
#修改变量值
data_1=999
echo "data_1="${data_1}
#命令替换,将命令执行的结果赋值给变量
data_1=`cat test.sh` #一般不使用反引号,而是用下面的方式,$() 支持嵌套,反引号不行
data_2=$(cat test.sh) #$() 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用
echo "data_1="${data_1} #如果${data_1}不加双引号,如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个。
echo "data_2="${data_2}
#只读变量重新赋值会出错
#data_4=222
#echo "data_4="${data_4}
#删除变量
unset data_1 data_2 data_3
echo "data_1="${data_1}
echo "data_2="${data_2}
echo "data_3="${data_3}
echo "data_4="${data_4}
#unset data_4 #unset不能删除只读变量,删除只读变量会出错
#局部变量、全局变量、环境变量
function func()
{
a=1 #全局变量
local b=2 #局部变量,只在函数内有用
export c=3 #环境变量
echo "a="${a}
echo "b="${b}
echo "c="${c}
}
func
echo "a="${a}
echo "b="${b}
echo "c="${c}
运行结果:

2、特殊变量($0、$n、$#、$*、$@、$?、$$)
| 变量 | 含义 |
|---|---|
| $0 | 当前脚本的文件名。 |
| $n(n≥1) | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。 |
| $# | 传递给脚本或函数的参数个数。 |
| $* | 传递给脚本或函数的所有参数。 |
| $@ | 传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同,下面讲解。 |
| $? | 上个命令的退出状态,或函数的返回值。 |
| $$ | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。 |
$* 和 $@ 都表示传递给函数或脚本的所有参数,当 $* 和 $@ 不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。但是当它们被双引号" "包含时,就会有区别了:
"$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。
"$@"仍然将每个参数都看作一份数据,彼此之间是独立的。
比如传递了 n 个参数,那么对于"$*"来说,这 n个参数会合并到一起形成一份数据,它们之间是无法分割的;而对于"$@"来说,这 n 个参数是相互独立的,它们是 n 份数据。
位置参数
运行Shell脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
同样,在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用$n的形式接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
这种通过$n的形式来接收的参数,在 Shell 中称为位置参数。
在讲解变量的命名时,我们提到:变量的名字必须以字母或者下划线开头,不能以数字开头;但是位置参数却偏偏是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”。
#!/bin/bash
#$0、$n、$#、$*、$@、$?、$$
#$0 当前脚本的文件名。
#$n(n≥1) 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。数字大于10最好用${n}形式
#$# 传递给脚本或函数的参数个数。
#$* 传递给脚本或函数的所有参数。
#$@ 传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同
#$? 上个命令的退出状态,或函数的返回值。
#$$ 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。""
echo "file name:$0" #$0表示当前shell脚本的文件名
echo ${1} #$n表示传递给脚本的参数,该参数需要在运行时赋值
echo ${2}
echo "parameter number:$#" #$#表示传递给脚本或函数的参数个数
echo "process:$*" #$*表示传递给she脚本的所有参数
echo "process:$@" #$*表示传递给she脚本的所有参数
echo "process ID:$$" #$$表示当前shell进程ID
function func()
{
echo ${1} #该参数表示传递给函数的参数,需要在调用函数时赋值
echo ${2}
echo ${3}
echo "parameter number:$#" #$#表示传递给函数的参数个数
echo "process:$*" #$*表示传递给函数的所有参数
echo "process:$@" #$@表示传递给函数的所有参数
return 10; #shell中函数的返回值是用来表示函数的退出状态,而不是数值,0~255之间,0表示成功,其它都表示失败对应的错误码
}
func 111 222 333
echo "func return:$?" #$?用来获取函数的返回值
#echo $? #在终端输入该命令可以获取上个命令的退出状态,大部分命令都是成功返回0,失败返回1
运行结果:
![]()
3、shell字符串
3.1、字符串的定义
字符串是 Shell 编程中最常用的数据类型之一,除了数字和字符串,也没有其他类型了。
字符串可以由单引号' '包围,也可以由双引号" "包围,也可以不用引号。它们之间是有区别的:
(1) 由单引号' '包围的字符串:
任何字符都会原样输出,在其中使用变量是无效的。字符串中不能出现单引号,即使对单引号进行转义也不行。
(2) 由双引号" "包围的字符串:
如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。 字符串中可以出现双引号,只要它被转义了就行。
(3)不被引号包围的字符串
不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
3.2、获取字符串的长度
${#string_name}
3.3、字符串的拼接
在脚本语言中,字符串的拼接(也称字符串连接或者字符串合并)往往都非常简单,例如:
在 PHP 中,使用.即可连接两个字符串;在 JavaScript 中,使用+即可将两个字符串合并为一个。
然而,在 Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接,非常简单粗暴。
3.4、字符串截取
Shell 截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。
(1)从指定位置开始截取
这种方式需要两个参数:除了指定起始位置,还需要截取长度,才能最终确定要截取的字符串。
既然需要指定起始位置,那么就涉及到计数方向的问题,到底是从字符串左边开始计数,还是从字符串右边开始计数。Shell 同时支持两种计数方式。
A、从左边开始计数
如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:${string: start :length}
其中,string 是要截取的字符串,start 是起始位置(从左边开始,从 0 开始计数),length 是要截取的长度(省略的话表示直到字符串的末尾)。
B、从右边开始计数
如果想从字符串的右边开始计数,那么截取字符串的具体格式如下:${string: 0-start :length}
和上面格式相比仅仅多了0-,这是固定的写法,专门用来表示从字符串右边开始计数。
这里需要强调两点:
从左边开始计数时,起始数字是 0(这符合程序员思维);从右边开始计数时,起始数字是 1(这符合常人思维)。计数方向不同,起始数字也不同。
不管从哪边开始计数,截取方向都是从左到右。
(2)从指定字符(子字符串)开始截取
这种截取方式无法指定字符串长度,只能从指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右边的所有字符,也可以截取左边的所有字符。
A、使用 # 号截取右边字符
使用#号可以截取指定字符(或者子字符串)右边的所有字符,具体格式如下:${string#*chars}
其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),*是通配符的一种,表示任意长度的字符串。*chars连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取)。
如果不需要忽略 chars 左边的字符,那么也可以不写*;
如果希望直到最后一个指定字符(子字符串)再匹配结束,那么可以使用##;
B、 使用 % 截取左边字符
使用%号可以截取指定字符(或者子字符串)左边的所有字符,具体格式如下:${string%chars*}
请注意*的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以*应该位于 chars 的右侧。
最后,我们对以上 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 左边的所有字符。 |
#!/bin/bash str1=output str1 #不加引号时变量值不能有空格 str2='output str2=${str1}' #单引号会将里面的内容全当字符处理,不会解析变量 str3="output str3=${str2}" #双引号会解析字符串里面的变量 echo "str1=$str1" #打印字符串变量的值 echo "str2=$str2" echo "str3=$str3" #获取字符串的长度 echo "str1_len=${#str1}" ##号可以用来获取字符串的长度 echo "str2_len=${#str2}" echo "str3_len=${#str3}" #字符串拼接 echo ${str1}${str2}${str3} #拼接字符串---连接 echo "${str1} ${str2} ${str3}" #拼接字符串---合并 echo "${str1}---${str2}---${str3}" #从左边开始数,然后在指定的位置开始截取字符串 echo ${str2:2:3} #从左边开始计数,在指定位置截取指定长度的字符串 echo ${str2:2} #从左边开始计数,在指定位置截取所有的字符串 #从右边开始数,然后在指定的位置开始截取字符串 echo ${str2:0-8:3} #从右边开始计数,在指定位置截取指定长度的字符串 echo ${str2:0-8} #从右边开始计数,在指定位置截取所有的字符串 #截取右边的字符 echo ${str2#*t} #当遇到第一个指定字符时就开始截取,这三种效果是一样的 echo ${str2#*ut} echo ${str2#*out} echo ${str2##*t} #在遇到最后一个指定字符才开始截取 #截取左边的字符 echo ${str2%t*} #从右边开始遇到第一个对应的字符就开始截取 echo ${str2%put*} echo ${str2%%t*} #从右边开始遇到最后一个对应的字符开始截取
运行结果:

4、shell数组
Shell 没有限制数组的大小,理论上可以存放无限量的数据。和 C++、Java、C# 等类似,Shell 数组元素的下标也是从 0 开始计数。
获取数组中的元素要使用下标[ ],下标可以是一个整数,也可以是一个结果为整数的表达式;当然,下标必须大于等于 0。
遗憾的是,常用的 Bash Shell 只支持一维数组,不支持多维数组。
4.1、Shell 数组的定义
在 Shell 中,用括号( )来表示数组,数组元素之间用空格来分隔。由此,定义数组的一般形式为:array_name=(ele1 ele2 ele3 ... elen)
注意,赋值号=两边不能有空格,必须紧挨着数组名和数组元素。Shell 是弱类型的,它并不要求所有数组元素的类型必须相同,数组元素可以是整形、字符型等。
Shell 数组的长度不是固定的,定义之后还可以增加元素。
此外,你也无需逐个元素地给数组赋值,下面的代码就是只给特定元素赋值:ages=([3]=24 [5]=19 [10]=12)
以上代码就只给第 3、5、10 个元素赋值,所以数组长度是 3。
4.2、获取数组元素
获取数组元素的值,一般使用下面的格式:${array_name[index]}
其中,array_name 是数组名,index 是下标。
使用@或*可以获取数组中的所有元素,例如:${nums[*]}、 ${nums[@]}
两者都可以得到 nums 数组的所有元素。
4.3、获取数组元素个数
利用@或*,可以将数组扩展成列表,然后使用#来获取数组元素的个数,格式如下:${#array_name[@]}、${#array_name[*]}
其中 array_name 表示数组名。两种形式是等价的,选择其一即可。
如果某个元素是字符串,还可以通过指定下标的方式获得该元素的长度,如下所示:${#arr[2]}
获取 arr 数组的第 2 个元素(假设它是字符串)的长度。
4.4、数组拼接
所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。
拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。具体格式如下:
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})
两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。
4.5、删除元素
在 Shell 中,使用 unset 关键字来删除数组元素,具体格式如下:unset array_name[index]
其中,array_name 表示数组名,index 表示数组下标。
如果不写下标,而是写成下面的形式:unset array_name
那么就是删除整个数组,所有元素都会消失。
4.6、shell关联数组(数组是字符串的数组)
关联数组也称为“键值对(key-value)”数组,键(key)也即字符串形式的数组下标,值(value)也即元素值。下标所对应的元素两者之间是关联的。
例如,我们可以创建一个叫做 color 的关联数组,并用颜色名字作为下标。
declare -A color color["red"]="#ff0000" color["green"]="#00ff00" color["blue"]="#0000ff"
也可以在定义的同时赋值:
declare -A color=(["red"]="#ff0000", ["green"]="#00ff00", ["blue"]="#0000ff")
不同于普通数组,关联数组必须使用带有-A选项的 declare 命令创建。
(1)访问关联数组元素
访问关联数组元素的方式几乎与普通数组相同,具体形式为:$(array_name["index"])
(2)获取所有元素的下标和值
使用下面的形式可以获得关联数组的所有元素值:${array_name[@]}、${array_name[*]}
(3)获取关联数组长度
使用下面的形式可以获得关联数组的长度:${#array_name[*]}、${#array_name[@]}
#!/bin/bash arr1=(1 2 3 35.66 'A' "hello word") #数组元素类型不是固定的,可以使任意类型 #获取数组元素的值 echo "arr1[0]=${arr1[0]}" #获取第0个元素的值 echo "arr1[4]=${arr1[4]}" echo "arr1[5]=${arr1[5]}" echo "arr1={${arr1[*]}}" #获取所有元素的值 echo "arr1={${arr1[@]}}" #获取所有元素的值 #修改数组元素的值 arr1[4]='F' echo "arr1[4]=${arr1[4]}" echo "arr1={${arr1[@]}}" #给数组怎增加一个元素 arr1[10]=10 #虽然下标为10,但是实际的个数不是由下标决定的 echo "arr1[10]=${arr1[10]}" echo "arr1={${arr1[@]}}" #获取所有元素的值 #可以不用给数组元素逐个赋值 arr2=([2]=2 [6]=6 [8]=8 [15]=15) #该数组事假只有4个元素 echo "arr2={${arr2[*]}}" #获取数组元素个数 arr3=(1 2 3 'A' "hello word!") echo "arr3={${arr3[*]}}" echo "arr3_len=${#arr3[*]}" echo "arr3_len=${#arr3[@]}" #获取数组中字符串元素的长度 echo "arr3[2]_len=${#arr3[2]}" echo "arr3[4]_len=${#arr3[4]}" str="To always face my adversity head on" echo "str=$str" echo "str_len=${#str}" #数组拼接 arr4=(${arr1[@]} ${arr2[@]}) echo "arr1={${arr1[@]}}" echo "arr2={${arr2[@]}}" echo "arr4={${arr4[@]}}" arr4=(${arr1[*]} ${arr2[*]}) echo "arr1={${arr1[@]}}" echo "arr2={${arr2[@]}}" echo "arr4={${arr4[*]}}" #删除数组或数组元素 echo "arr1={${arr1[@]}}" #删除元素 unset arr1[0] echo "arr1={${arr1[@]}}" unset arr1[3] echo "arr1={${arr1[@]}}" unset arr1 #删除数组 echo "arr1={${arr1[@]}}" #关联数组(下标是字符串的数组) declare -A color color["red"]="#ff0000" color["green"]="#00ff00" color["blue"]="#0000ff" echo "color["red"]=${color["red"]}" #输出关联数组元素的值 echo "color["green"]=${color["green"]}" echo "color["blue"]=${color["blue"]}" echo "color=${color[*]}" #获取数组所有元素的值 echo "color=${color[@]}" echo "color[i]=${!color[*]}" #获取数组所有下标的值 echo "color[i]=${!color[@]}" echo "color_len=${#color[*]}" #获取关联数组的长度 echo "color_len=${#color[@]}"
运行结果:



浙公网安备 33010602011771号