shell变量详解

变量的作用域

每个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 同set
  • exprot 显示和设置环境变量的值

撤销、删除变量

  • 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'

declare命令详解

源文件名

小写,如果需要的话使用下划线分隔单词。
这是为了和在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 ~]# 

扩展:

  1. 字符串长度统计方法
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]#
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值