shell 脚本 - 变量
变量基础概念
变量类型
内置变量(环境变量) ,如:PS1,PATH,UID,HOSTNAME,$
,
B
A
S
H
P
I
D
,
P
P
I
D
,
,BASHPID,PPID,
,BASHPID,PPID,?,HISTSIZE 等
用户自定义变量
数据类型:字符和数值。数值包含整型、浮点型,bash 不支持浮点数
变量命名法则
1 不能使用程序中的关键字和内置变量,如:if,for
2 只能使用数字、字母及下划线,且不能以数字开头。注意:不支持短横线“-”,和主机名相反
3 见名知意,建议用英文单词命名,并体现实际作用,最好不要用简写
4 统一命名规则:驼峰命名法(studentname),大驼峰(StudentName),小驼峰(studentName)
5 变量名大写:STUDENT_NAME
6 局部变量小写
7 函数名小写
变量定义和应用
变量的生效范围等标准划分变量类型
普通变量:生效范围为当前shell 进程;对当前shell 之外的其他shell 进程,包括当前shell 的子shell 进程均无效
环境变量:生效范围为当前shell 进程及其子进程
本地变量:生效范围为当前shell 进程中某代码片段,通常指函数
变量赋值
name='value'
value的多种形式
直接字符串 name='root'
变量引用 name="$USER"
命令引用 name=`COMMAND` 或者 name=$(COMMAND)
需要注意的是:
变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存。脚本中的变量也会随着脚本结束,自动删除
变量引用
$name 或 ${name} 建议使用${name}
"$name" 弱引用,其中的变量引用会被替换为变量值
'$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
范例:变量的各种赋值方式和引用
#变量的赋值方式
[root@CentOS8 ~]#TITLE='cto'
[root@CentOS8 ~]#echo $TITLE
cto
[root@CentOS8 ~]#TITLE='cto'
[root@CentOS8 ~]#echo $TITLE
cto
[root@CentOS8 ~]#echo "i am $TITLE"
i am cto
[root@CentOS8 ~]#echo 'i am $TITLE'
i am $TITLE
[root@CentOS8 ~]#FILE=`ls /run`
[root@CentOS8 ~]#echo $FILE
agetty.reload auditd.pid console cron.reboot cryptsetup dbus faillock fsck initctl initramfs lock log mount NetworkManager plymouth rsyslogd.pid sepermit setrans sshd.pid sssd.pid sudo systemd tmpfiles.d tuned udev user utmp vmware
#变量的引用
[root@CentOS8 ~]#NAME=dawn
[root@CentOS8 ~]#AGE=17
[root@CentOS8 ~]#echo $NAME $AGE
dawn 17
[root@CentOS8 ~]#echo $NAME$AGE
dawn17
[root@CentOS8 ~]#echo $NAME_$AGE
17
[root@CentOS8 ~]#echo ${NAME}_$AGE
dawn_17
#变量的间接赋值和引用,ps:原变量的值修改后,被赋值的变量的值不会随之变更
[root@CentOS8 ~]#TITLE=cto
[root@CentOS8 ~]#NAME=dawn
[root@CentOS8 ~]#TITLE=$NAME
[root@CentOS8 ~]#echo $NAME
dawn
[root@CentOS8 ~]#echo $TITLE
dawn
[root@CentOS8 ~]#NAME=haha
[root@CentOS8 ~]#echo $NAME
haha
[root@CentOS8 ~]#echo $TITLE
dawn
#利用变量实现动态命令
[root@CentOS8 ~]#CMD=hostname
[root@CentOS8 ~]#$CMD
CentOS8.dawn
变量的显示和删除
set 显示已定义的所有变量
unset <name> 删除变量name
范例
[root@CentOS8 ~]#NAME=dawn
[root@CentOS8 ~]#TITLE=ceo
[root@CentOS8 ~]#echo $NAME $TITLE
dawn ceo
[root@CentOS8 ~]#unset NAME TITLE
[root@CentOS8 ~]#echo $NAME $TITLE
[root@CentOS8 ~]#
环境变量
- 可使子进程(子子孙孙进程)继承父进程的变量,但无法让父进程使用子进程的变量
- 一旦子进程修改从父进程继承的变量,会将新的值传递给孙子进程,不影响父进程的值
- 一般只在系统配置文件中使用,在脚本使用较少
声明赋值引用
#声明并赋值
export name=VALUE
declare -x name=VALUE
#也可先赋值再声明
name=VALUE
export name
#变量引用
$name 或 ${name}
显示所有环境变量
[root@CentOS8 ~]#env
[root@CentOS8 ~]#printenv
[root@CentOS8 ~]#export
[root@CentOS8 ~]#declare -x
删除变量
unset name
只读变量
只能声明定义,后续不能修改和删除,即常量
声明查看
#声明
readonly name 或declare -r name
#查看
readonly [-p]
declare -r
范例
#声明常量PI
[root@CentOS8 ~]#readonly PI=3.1415926
[root@CentOS8 ~]#echo $PI
3.1415926
#无法修改常量
[root@CentOS8 ~]#PI=3.14
-bash: PI: readonly variable
#无法删除
[root@CentOS8 ~]#unset PI
-bash: unset: PI: cannot unset: readonly variable
#退出当前shell,常量就被销毁了
[root@CentOS8 ~]#exit
位置变量
在bash shell 中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,...$n 对应第1个,第2个等第n个参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数视为一个字符串
$@ 传递给脚本的所有参数,每个参数视为独立字符串
$# 传递给脚本的参数的个数
$$ 脚本执行的过程ID号
ps:$@ $* 只有在被双引号抱起来的时候才会有差异
清空所有位置变量
set --
范例
[root@CentOS8 script]#cat args.sh
#!/bin/bash
#********************************************************************
# Author:dawn
# Date:2020-08-08 10:21:18
# FileName:args.sh
# URL:https://blog.csdn.net/xiao_dan_
# Version:1.0
# Description:The test script
#********************************************************************
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "10st arg is ${10}"
echo "11st arg is ${11}"
echo "\$# The number of arg is $#"
echo "\$* All args are $*"
echo "\$@ All args are $@"
echo "The scriptname is `basename $0`"
echo "\$\$ PID is $$"
[root@CentOS8 script]#bash args.sh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
$# The number of arg is 26
$* All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
$@ All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is args.sh
$$ PID is 3052
范例- @ 和 @ 和 @和* 的区别
#$@ 和$* 的区别 --主要用在轮询的时候
[root@CentOS8 script]#cat test.sh
echo "\$* 展示的所有参数:$*"
for i in "$*";do
echo $i
done
echo "\$@ 展示的所有参数:$@"
for i in "$@";do
echo $i
done
[root@CentOS8 script]#bash test.sh dawn li 22 33
$* 展示的所有参数:dawn li 22 33
dawn li 22 33
$@ 展示的所有参数:dawn li 22 33
dawn
li
22
33
范例-利用软链接实现同一个脚本不同功能
[root@CentOS8 script]#vim ln.sh
#!/bin/bash
echo $0
#设置软链接
[root@CentOS8 script]#ln -snf ln.sh a.sh
[root@CentOS8 script]#ln -snf ln.sh b.sh
#执行软链接
[root@CentOS8 script]#bash a.sh
a.sh
[root@CentOS8 script]#bash b.sh
b.sh
退出状态码变量
在shell 脚本中使用 $?
保存程序执行状态码的相关数字,不同的值反应成功或失败,$?
取值范围在0-255
$? 上一条命令执行后的状态,0:执行正常,非零为异常,一般结果为1
自定义退出状态码
exit [n] n的取值范围在0-255
范例
[root@CentOS8 ~]#curl http://www.wangxiaochun.com &> /dev/null
[root@CentOS8 ~]#echo $?
0
ps:
- 脚本中一旦遇到exit 命令,脚本会立即终止;终止退出状态码取决于exit 命令后的数字
- 如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
脚本安全和set
set
可用来定制shell 环境
set 命令实现脚本安全
-u 在扩展一个没有设置的变量时,显示错误信息,等同set -o nounset
-e 如果一个命令返回一个非0退出状态值(失败)就退出,等同set -o errexit
-o option 显示,打开或关闭选项
显示选项:set -o
打开选项:set -o 选项
关闭选项:set +o 选项
-x 当执行命令时,打印命令及其参数,类似bash -x
范例
[root@CentOS8 ~]#set -o
allexport off
braceexpand off
emacs on
……省略……
$- 变量
h hashall,打开选项后,shell 会将命令所在的路径hash 下来,避免每次都要查询。通过set +h 将h 选项关闭
i interactive-comments,包含这个选项说明当前的shell 是一个交互式的shell。所谓交互式shell,在脚本中,i 选项是关闭的
m moniter,打开监控模式,可通过job control来控制进程的停止、继续,后台或前台执行等
B braceexpand,大括号扩展
H history,H选项打开,可展开历史列表的命令,可通过感叹号! 来完成,例如:!! 返回最近一个历史命令,!n 返回第n 个历史命令
范例
[root@CentOS8 ~]#echo $-
himBHs
[root@CentOS8 ~]#echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@CentOS8 ~]#set +B
[root@CentOS8 ~]#echo $-
himHs
[root@CentOS8 ~]#echo {1..10}
{1..10}