第三章、shell变量和数组
正文
第三章、shell变量和数组
0、总结
将总结放在前面是方便复习。
# 变量取值 echo ${name}acwing # 只读变量 declare -r constant_variable_name readonly constant_variable_name # 局部变量->全局变量 export global_variable_name declare -x global_variable_name export PATH=$PATH:/home/xyg/anaconda/bin # 全局变量->局部变量 declare +x name # 将全局变量转换为局部变量 # 删除变量 unset var_name # 字符串 echo "hello, $name \"hh\"" echo ${#name} # 输出字符串长度 11 echo ${name:3:5} # 输出字符串name下标从3开始,长度为5的子串 -> ky-li # 位置参数 echo "file_name $0" echo "position 1: $1" echo "position 2: $2" # 数组 names=(xyg 'lucky-light', "I love acwing", `ls`) names[0]=xyg names[1]='lucky-light' names[2]="I love acwing" echo ${names[0]} # 输出整个数组和他的长度 echo ${names[@]} echo ${names[*]} echo ${#names[@]} echo ${#names[*]}
参数 | 含义 |
---|---|
$# |
代表文件传入的参数个数,如上例中值为3 |
$* |
由所有参数构成的用空格隔开的字符串,如上例中值为"$1 $2 $3" |
$@ |
每个参数分别用双引号括起来的字符串,如上例中值为"$1" "$2" "$3" |
$$ |
脚本当前运行的进程ID |
$? |
上一条命令的退出状态(注意不是stdout,而是exit code)。0表示正常退出,其他值表示错误 |
$(command) |
返回command 这条命令的stdout(可嵌套) |
`command` | 返回command 这条命令的stdout(不可嵌套) |
1、变量
变量,指值可以变的量。是编程语言中最为重要的部分。因为 Shell
脚本所针对的是文件管理,所以定义、使用、删除等语法会略显不同(和C、Python相比)。
变量定义
bash
脚本中,变量的类型都为字符串类型的,普通变量主要存在三种定义方式,如下所示:
s1=xyg s2='xyg' s3="xyg"
使用变量
借助于字符$
,可以取出变量的数值,也可以借助{}
圈中变量名,帮助解释器识别变量边界。
#! /bin/bash name=lucky-light echo $name echo ${name} echo ${name}acwing
只读变量
只读变量,或者是常量,bash
中有两种定义方式,使用declare -r variable_name
或者是 readonly variable_name
。
#! /bin/bash # define the constant name=lucky-light readonly name name=xyg
报错信息: line 6: name: readonly variable
#! /bin/bash # define the constant name=lucky-light declare -r name name=xyg
报错信息: line 6: name: readonly variable
删除变量
在其他语言中,我们往往不需要删除变量,变量也存在自己的作用域和生命周期。bash
脚本中提供了删除变量的方法。需要关键字 unset
。
unset
变量之后,未定义的变量就是一个空字符串。
注意 readonly
只读变量不予许删除 unset: name: cannot unset: readonly variable。
#! /bin/bash # define the constant name=lucky-light echo $name unset name echo $name # this will output a blank line because we unset the variable
变量类型
变量是存在作用域的,bash
脚本的作用域则是通过是否可以跨进程来区分。分为了自定义变量(局部变量)和环境变量(全局变量)。
- 自定义变量(局部变量)
子进程不能访问的变量 - 环境变量(全局变量)
子进程可以访问的变量
bash
脚本提供了局部变量和全局变量的相互转化。
- 自定义变量 -> 全局变量
主要有两种方法export local_varialbe
或者是declare -x local_variable
name=lucky-light export name # 第一种方法 declare -x name # 第二种方法
- 全局变量 -> 自定义变量
export name=lucky-light # 定义全局变量 declare +x name # 将全局变量转换为局部变量
为了验证结果,可以 bash
查看子进程内容。或者是我们调用其他脚本开的也是一个新的进程。
#! /bin/bash # define the constant name=lucky-light echo $name unset name echo $name # this will output a blank line because we unset the variable echo $name2 # to see the global variable can be get
结果如下:
字符串
字符串是 bash 脚本中最基本的数据,所有的数据存储都默认为字符串存储。
字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号与双引号的区别:
- 单引号中的内容会原样输出,不会执行、不会取变量;如
echo '${name}'
中${name}
只会原样输出,不会取出数值。 但是 echo -e指名的转义,还是会转义的 - 双引号中的内容可以执行、可以取变量;如
echo "${name}"
中${name}
会取出变量中存储的内容。
具体而言,单引号和双引号用于变量值出现空格时,比如 name=zhang san 这样执行就会出现问题,而必须用引号括起来,比如 name="zhang san"。
不过,引号有单引号和双引号之分,二者的主要区别在于,被单引号括起来的字符都是普通字符,就算特殊字符也不再有特殊含义;而被双引号括起来的字符中,""代表引用变量的值,而反引号代表引用命令。
name=lucky-light # 不用引号 echo 'hello, $name \"hh\"' # 单引号字符串,输出 hello, $name \"hh\" echo "hello, $name \"hh\"" # 双引号字符串,输出 hello, lucky-light "hh"
输出结果
[vivo4@~/xyg/test]$./1.sh hello, $name \"hh\" hello, lucky-light "hh"
获取字符串长度: 使用${#name}
name='lucky-light' echo ${#name} # 输出字符串长度 11
提取子串: 使用${name:start_idx:sub_len}
。对于源字符串而言,下标从0
开始
name='lucky-light' echo ${name:3:5} # 输出字符串name下标从3开始,长度为5的子串 -> ky-li
2、默认变量
默认变量是bash
中已经给定,具备特殊用途的变量,有文件参数变量和其他相关变量。
文件参数变量
在执行 shell
脚本时,可以向脚本传递参数。$1
是第一个参数,$2
是第二个参数,以此类推。
特殊的,$0
是第0个参数,文件名(包含路径)。比如说 './test_bash.sh' 或者是 '/home/xyg/test/test_bash.sh',具体得看执行 bash
文件时候,第0个参数的时候,你用的什么。
在 test_bash.sh
,测试查看位置参数。
#! /bin/bash echo "file_name $0" echo "position 1: $1" echo "position 2: $2" echo "position 3: $3"
运行该脚本
chmod a+x test_bash.sh ./test_bash.sh xyg lucky-light acw
运行结果
file_name ./test_bash.sh position 1: xyg position 2: lucky-light position 3: acw
其他参数相关变量
参数 | 含义 |
---|---|
$# |
代表文件传入的参数个数,如上例中值为3 |
$* |
由所有参数构成的用空格隔开的字符串,如上例中值为"$1 $2 $3" |
$@ |
每个参数分别用双引号括起来的字符串,如上例中值为"$1" "$2" "$3" |
$$ |
脚本当前运行的进程ID |
$? |
上一条命令的退出状态(注意不是stdout,而是exit code)。0表示正常退出,其他值表示错误 |
$(command) |
返回command 这条命令的stdout(可嵌套) |
`command` | 返回command 这条命令的stdout(不可嵌套) |
注意点:
- stdout 和 exit code 的区别
stdout 就好像是 c++中的 printf操作,而 exit code 是函数 return 的数值。因此$?
和$(command)
有不同的用处。 $*
和$@
两者的区别不大,都是将位置参数取出并展示,极个别情况下才会出现不同。$(command)
和command
都是bash
中非常常用的形式,注意$(command)
是可以嵌套的。
3、数组
为了方便循环操作大批数据,大多数语言都设有数组这一概念。bash
中数组中可以存放多个不同类型的值(其实都是字符串),只支持一维数组,初始化时不需要指明数组大小。
数组的下标从 0 开始
定义
数组用小括号表示,元素之间用空格隔开。
names=(xyg 'lucky-light', "I love acwing", `ls`)
也可以直接定义数组中某个元素的值:
names[0]=xyg names[1]='lucky-light' names[2]="I love acwing" names[3]=`ls`
读取数值
${array_name[idx]}
组合获取 array_name
数组下标 idx
的数值。
names=(xyg 'lucky-light', "I love acwing", "`ls`") echo ${names[0]} echo ${names[1]} echo ${names[2]} echo ${names[3]}
注意,"ls
"是加单引号、双引号、和不加单引号双引号结果是完全不一样的。
'`ls`' # 加单引号 "`ls`" # 加双引号 `ls` # 不加引号 names[3]=`ls` # 单个赋值 # 单引号结果 xyg lucky-light, I love acwing, `ls` # 双引号结果 xyg lucky-light, I love acwing, 1.sh test.csv test_bash.sh # 不加引号结果 xyg lucky-light, I love acwing, 1.sh
加单引号, ` 符号不会被解析。
加双引号 ,` 符号会被解析,并且 ls
指令的结果将会作为整体字符串输出,
不加引号,ls
指令的结果因为会间隔空格,names[3], names[4]
会依次获取数值 value
但是 单个赋值 时候, ls
所有的结果都会放在names[3]
中,等价于加入了双引号
整个数组
输出整个数组的语法。(当然,你也可以自己遍历)
${array_name[@]} # 第一种写法 ${array_name[*]} # 第二种写法
#! /bin/bash names=(lucky-light, 'acwing', "xyg", "`ls`") echo ${names[@]} echo ${names[*]}
输出结果,不同数组元素使用 逗号 分隔
lucky-light, acwing, xyg, 1.sh test.csv test_bash.sh lucky-light, acwing, xyg, 1.sh test.csv test_bash.sh
数组长度
类似于字符串
${#array[@]} # 第一种写法 ${#array[*]} # 第二种写法
#! /bin/bash names=(lucky-light, 'acwing', "xyg", "`ls`") echo ${names[@]} echo ${names[*]} echo ${#names[@]} echo ${#names[*]} echo '############### tmp ###############' tmp_str=${names[@]} echo ${tmp_str} echo ${#tmp_str}
输出结果,最有趣的是将 tmp_str=${names[@]}
数组整体信息赋值给 字符串变量后,使用 #
计算长度,是不同的。
也就是说计算数组长度时候,调用的 api 完全和计算字符串长度 不同。
lucky-light, acwing, xyg, 1.sh test.csv test_bash.sh lucky-light, acwing, xyg, 1.sh test.csv test_bash.sh 4 4 ############### tmp ############### lucky-light, acwing, xyg, 1.sh test.csv test_bash.sh 52
数组单独赋值
数组的定义是允许我们给数组单个元素跳跃赋值的,但是他的空间分配如何,间隔的元素又是否分配了空间呢?
--> bash 数组赋值是内存优化过的,未赋值便不给分配空间
#! /bin/bash names[0]=xyg names[1]='lucky-light' names[2]="I love acwing" names[1000]=`ls` echo ${names[@]} # 输出全部数组 echo ${names[*]} # 输出全部数组 echo ${#names[@]} # 输出数组长度 echo ${#names[*]} # 输出数组长度 echo 'after echo names[3]' echo names[3] # 测试一下 echo ${#names[@]} # 输出数组长度,发现不变 echo 'after names[3]=test' names[3]=test echo ${#names[@]} # 数组长度会 + 1 echo 'give the empty' names[10]='' echo ${#names[@]} # 数组长度会 + 1,即使给的是空串
输出结果,可以发现,解释 echo names[3]
之后,内核仍不会给这个未定义的变量分配内存,也不会算入计数,只有真正赋值才可以。
xyg lucky-light I love acwing 1.sh test.csv test_bash.sh xyg lucky-light I love acwing 1.sh test.csv test_bash.sh 4 4 after echo names[3] names[3] 4 after names[3]=test 5 give the empty 6
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)