变量的作用域
每个shell进程中定义的变量是隔离的,其作用域为当前shell,举个例子:如图,父子shell进程中变量的作用域演示
退出子shell执行exit
执行shell脚本的方式以及脚本中变量的作用域
定义简单脚本
执行脚本
- 方式1 :
sh aaa.sh
或者bash aaa.sh
指定解释器执行,所以脚本中可以不用指定首行的#!/bin/sh
脚本执行调用bash会开启一个子shell,name变量的作用域为该子shell,执行完成后子shell退出,当前shell输出name为空
- 方式2:
./aaa.sh
脚本文件需要可执行权限(chmod +x aaa.sh
)
脚本首行需要指定bash解释器(#!/bin/sh
)
- 方式3:
source aaa.sh
或者. aaa.sh
在当前shell环境加载脚本,所以脚本中可以不用指定首行的#!/bin/sh
在当前shell环境加载脚本,所以变量在当前脚本生效
环境变量、全局变量、局部变量
环境变量
环境变量定义特定的文件中
- 全局配置文件
/etc/profile
/etc/bashrc
,可以理解为系统环境变量 - 用户个人配置文件
~/.bash_profile
~/.bashrc
,可以理解为用户环境变量 - 环境变量加载流程原理介绍 自行百度
全局变量、局部变量
Shell中变量都是全局变量
局部变量,函数中,使用local关键字
全局变量的作用域都是当前shell,局部变量只在函数内部有效
函数本身也是全局变量
只读变量
只读变量,顾名思义就是常量
,初始化后不能再赋值,shell结束只读变量失效
使用 readonly 或者 declare -r 来确保变量只读。
因为全局变量在shell中广泛使用,所以在使用它们的过程中捕获错误是很重要的。当你声明了一个变量,希望其只读,那么请明确指出。
readonly命令详解
特殊变量
shell的特殊变量用于脚本传参/函数传参
$0
获取shell脚本的文件名$n
获取脚本的第n个参数$#
参数总个数$*
获取所有参数$@
获取所有参数
简单演示下:
[root@taotaoplus demo]# cat aaa.sh
#!/bin/bash
echo '脚本文件名:$0:' && echo "$0"
echo '脚本第一个参数$1:' && echo "$1"
echo '脚本第一个参数$2:' && echo "$2"
echo '脚本参数总个数$#:' && echo "$#"
func() {
echo '脚本文件名:$0:' && echo "$0"
echo '函数第一个参数$1:' && echo "$1"
echo '函数第一个参数$2:' && echo "$2"
echo '函数第一个参数$3:' && echo "$3"
echo '函数参数总个数$#:' && echo "$#"
}
func 函数参数1 函数参数2 函数参数3
$*
和$@
的区别
都是获取所有参数,
echo $*
和 echo $@
结果相同,显示所有参数,空格间隔
参数1 参数2 参数3
echo "$*"
显示结果如下(ps:echo '$*'
不能使用单引号,单引号字符串原样打印)
参数1 参数2 参数3
echo $@
(ps:for循环遍历时更友好)
参数1
参数2
参数3
演示一下
[root@taotaoplus demo]# cat aaa.sh
#!/bin/bash
echo "输出 \"\$*\" 中的每个参数"
for var in "$*"
do
echo "$var"
done
echo "输出 \"\$@\" 中的每个参数"
for var in "$@"
do
echo "$var"
done
[root@taotaoplus demo]# sh aaa.sh 参数1 参数2 参数3
输出 "$*" 中的每个参数
参数1 参数2 参数3
输出 "$@" 中的每个参数
参数1
参数2
参数3
特殊状态变量
-
$?
上一次执行状态的返回值,非0表示执行失败
脚本退出状态的返回值:exit 0~255 -
$$
当前shell脚本的PID
-
$!
上一次后台进程的PID
ps:后台执行一条命令并将日志输出到黑洞文件
nohup ping baidu.com & 1> /dev/null
-
$_
上次执行命令的最后一个参数
相关命令
输出变量
set
输出 全局变量和环境变量env
输出 环境变量declare
同setexprot
显示和设置环境变量的值
撤销、删除变量
unset 变量名
变量命名规范
变量名必须是以字母或下划线字符“_”开头,后面跟字母、数字或下划线字符。不要使用?、*或其他特殊字符命名你的变量。
注意:
变量名和等号之间不能有空格;
首个字符必须为字母(a-z A-Z)
中间不能有空格,可以是下划线(ps:空格会识别为 命令 参数
)
不能使用标点符号
不能使用bash中的关键字
函数名
使用小写字母,并用下划线分隔单词
使用双冒号 :: 分隔库
函数名之后必须有圆括号
关键词function是可选的,但必须在一个项目中保持一致。(PS:当函数名后存在 () 时,关键词 function是多余的。)
变量名
如函数名。
见名知意,如循环的变量名应该和循环的任何变量同样命名。
for zone in ${zones}; do
something_with "${zone}"
done
常量和环境变量名
声明在文件的顶部,全部大写,用下划线分隔。
常量和任何导出到环境中的变量都应该大写。
# 常量 只读
# readonly标记变量只读,如果对其进行重新赋值,会提示错误(readonly)
readonly PATH_TO_FILES='/some/path'
# 常量 + 环境变量
# r 将变量设置为只读
# x 指定的变量会成为环境变量,可供shell以外的程序来使用
declare -xr ORACLE_SID='PROD'
源文件名
小写,如果需要的话使用下划线分隔单词。
这是为了和在Google中的其他代码风格保持一致: maketemplate 或者 make_template ,而不是 make-template 。
变量与shell子串
${变量} # 返回变量值
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name}
taotaoplus
${#变量} # 返回变量长度
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${#name}
10
${变量:start} # 返回变量start索引(含)之后的字符
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name:6}
plus
${变量:start:length} # 返回变量start索引(含)之后的length个字符
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name:3:3}
tao
########这部分后面单独举例演示#################
${变量#word} # 从变量开头删除最短匹配的word字串
${变量##word} # 从变量开头删除最长匹配的word字串
${变量%word} # 从变量结尾删除最短匹配的word字串
${变量%%word} # 从变量结尾删除最长匹配的word字串
######################################
${变量/pattern/str} # 用str替换第一个匹配到的pattern
${变量//pattern/str} # 用str替换所有匹配到的pattern
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name/tao/di}
ditaoplus
[root@taotaoplus ~]# echo ${name//tao/di}
didiplus
# str 为空时
[root@taotaoplus ~]# echo ${name/tao/}
taoplus
[root@taotaoplus ~]# echo ${name//tao/}
plus
[root@taotaoplus ~]#
扩展:
- 字符串长度统计方法
cat test.tst wc -l # 统计文件的行数
cat test.tst wc -l # 统计文件中最长哪一行的字符串长度
echo ${变量} |wc -L # 统计变量长度
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name} |wc -L
10
echo ${变量} |awk '{print length($0)}' # 统计变量长度
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# echo ${name} |awk '{print length($0)}'
10
expr length ${变量} # 返回变量长度最简单
[root@taotaoplus ~]# name="taotaoplus"
[root@taotaoplus ~]# expr length ${name}
10
${#变量} # 返回变量长度最快最简单
字串的最长匹配与最短匹配
##
和%%
表示最长匹配,#
和%
表示最短匹配
键盘上#在%
前面,所以#
是对左边部分处理,%
是对右边部分处理
举个栗子:
# 获取文件名后缀,即删除 . 左边的部分
[root@taotaoplus demo]# echo ${filepath}
/root/demo/aaa.tar.gz
[root@taotaoplus demo]# echo ${filepath#*.} # 最短匹配,匹配到左边的/root/demo/aaa. 删除
tar.gz
[root@taotaoplus demo]# echo ${filepath##*.} # 最长匹配,匹配到左边的/root/demo/aaa.tar 删除
gz
# 获取文件名,即删除最后一个 / 左边的部分
[root@taotaoplus demo]# echo ${filepath}
/root/demo/aaa.tar.gz
[root@taotaoplus demo]# echo ${filepath#*/} # 最短匹配,匹配到左边的/ 删除,得不到文件名
root/demo/aaa.tar.gz
[root@taotaoplus demo]# echo ${filepath##*/} # 最长匹配,匹配到左边的/root/demo/ 删除,得到文件名
aaa.tar.gz
# 获取文件路径,即删除最后一个 / 右边的部分
[root@taotaoplus demo]# echo ${filepath}
/root/demo/aaa.tar.gz
[root@taotaoplus demo]# echo ${filepath%%/*} # 最长匹配,匹配到右边的/root/demo/aaa.tar.gz 删除,空
[root@taotaoplus demo]# echo ${filepath%/*} # 最短匹配,匹配到右边的/aaa.tar.gz 删除,得到文件路径
/root/demo
# 去除文件名后缀,即删除 . 后面的部分
[root@taotaoplus demo]# echo ${filepath}
/root/demo/aaa.tar.gz
[root@taotaoplus demo]# echo ${filepath%.*} # 最短匹配,匹配到右边的.gz 删除
/root/demo/aaa.tar
[root@taotaoplus demo]# echo ${filepath%%.*} # 最长匹配,匹配到右边的.tar.gz 删除
/root/demo/aaa
变量判空的扩展语法
四种对变量值的判断与处理
# 1. 如果name变量的值为空,返回 “taotaoplus”
res=${name:-"taotaoplus"}
[root@taotaoplus demo]# unset name;unset res
[root@taotaoplus demo]# res=${name:-"taotaoplus"}
[root@taotaoplus demo]# echo $name;echo $res
taotaoplus
[root@taotaoplus demo]#
# 2. 如果name变量的值为空,什么都不做,否则返回 “taotaoplus” (注意这里时不返回name的值的)
res=${name:+"taotaoplus"}
[root@taotaoplus demo]# unset name;unset res
[root@taotaoplus demo]# res=${name:+"taotaoplus"}
[root@taotaoplus demo]# echo $name;echo $res
[root@taotaoplus demo]# name=taotao
[root@taotaoplus demo]# res=${name:+"taotaoplus"}
[root@taotaoplus demo]# echo $name;echo $res
taotao
taotaoplus
[root@taotaoplus demo]#
[root@taotaoplus demo]#
# 3. 如果name变量的值为空,则“taotaoplus”替代name变量的值,并且返回 “taotaoplus”,否则返回name的值
res=${name:="taotaoplus"}
[root@taotaoplus demo]# unset name;unset res
[root@taotaoplus demo]# res=${name:="taotaoplus"}
[root@taotaoplus demo]# echo $name;echo $res
taotaoplus
taotaoplus
[root@taotaoplus demo]# unset name;unset res
[root@taotaoplus demo]# name="taotao"
[root@taotaoplus demo]# res=${name:="taotaoplus"}
[root@taotaoplus demo]# echo $name;echo $res
taotao
taotao
[root@taotaoplus demo]#
# 如果name变量的值为空,给出的字符串("error:name is empty")当作stderr(标准错误输出)输出,否则返回name的值
res=${name:?"error:name is empty"}
[root@taotaoplus demo]# unset name;unset res
[root@taotaoplus demo]# res=${name:?"error:name is empty"}
-bash: name: error:name is empty
[root@taotaoplus demo]# echo $name;echo $res
[root@taotaoplus demo]#