
Shell 脚本编程之变量
一、bash的特殊字符的意义
1.1、通配符和其他特殊符号
1.1.1 通配符
通配符 | 作用 |
---|---|
? | 匹配一个任意字符 |
* | 匹配0个或任意多个任意字符,也就是可以匹配任何内容 |
[] | 匹配中括号中任意一个字符。例如:[abc]代表一定匹配一个字符,或者是a,或者是b,或者是c |
[-] | 匹配中括号中任意一个字符,-代表一个范围。例如:[a-z]代表匹配一个小写字母 |
[^] | 逻辑非,代表匹配不是中括号内的一个字符,例如:[ ^ 0-9 ]表示匹配一个不是数字的字符 |
1.1.2 其他特殊符号
符号 | 作用 |
---|---|
’ ’ | 单引号(强引用)。单引号中所有的特殊符号,如‘$‘和‘`’(反引号)都没有特殊含义。 |
" " | 双引号(弱引用)。在双引号中特殊符号都没有特殊含义,但是"$" 和" "是例外,拥有“调用变量的值”,“引用命令”和“转义符”的特殊含义 |
``(在table键的上面) | 反引号。反引号括起来的内容是系统命令,在Bash中会先执行它。和( ) 作 用 一 样 , 不 过 推 荐 使 用 ()作用一样,不过推荐使用()作用一样,不过推荐使用(),因为反引号非常容易看错。 |
$() | 用来引用系统命令 |
# | 在Shell脚本中,#开头的行代表注释,除此之外脚本的第一行(#!)和超级管理员用户(#) |
$ | 用于调用变量的值,如需要调用变量name的值时,需要用$name的方式得到变量的值 |
\ | 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。如$将输出"$"符号,而不当做是变量引用 |
! | 取反 |
$? | 此变量值在使用的时候,返回的是最后一个命令、函数、或脚本的退出状态码值,如果没有错误则是0,如果为非0,则表示在此之前的最后一次执行有错误。 |
/ | 在作为运算符的时候,表示除法符号,比如a=4/2 |
$$ | 进程ID变量,这个变量保存了运行当前脚本的进程ID值。 |
& | 如果命令后面跟上一个&符号,这个命令将会在后台运行。 |
() | 用于一串命令执行时,()中的命令会在子shell中运行 |
{} | 用于一串命令执行时,{}中的命令会在当前shell中执行,也可以用于变量的替换和变形 |
- 注意:反引号
``
在系统中容易被看成单引号,所以使用时,可以用$()
代替
定义变量
[root@myx01~]$ a=hello
[root@myx01~]$ echo $a
hello
`` 和 $( )功能相同
[root@myx01~]$ a=$(date)
[root@myx01~]$ echo $a
2023年 09月 27日 星期三 15:45:38 CST
[root@myx01~]$ a=`date`
[root@myx01~]$ echo $a
2023年 09月 27日 星期三 15:45:59 CST
反引号``和$()的区别:
1. 反引号容易和单引号混淆;
2. 反引号在多层嵌套使用时需要使用(\`)处理,而使用$(ls)就没有这样的问题。
转义符“\”,
-e:开启转义
-n:表示换行
-t:水平制表符
-v:垂直制表符
-b 表示删除前一个字符
() 和 { }
[root@myx01~]$ b=`hostname`
[root@myx01~]$ echo $b
myx01
# 小括号中可以运子shell,子shell中的a和父shell的a值不冲突
[root@myx01~]$ echo $a
2023年 09月 27日 星期三 15:45:59 CST
[root@myx01~]$ (a=test;echo $a)
test
[root@myx01~]$ echo $a
2023年 09月 27日 星期三 15:45:59 CST
# 花括号的作用会替换原有系统的变量的值,在最后一个变量后需要加 ";" 同时花括号的左右需要加空格
[root@myx01~]$ b=123
[root@myx01~]$ echo $b
123
[root@myx01~]$ { b=abc;echo $b; }
abc
[root@myx01~]$ echo $b
abc
二、Bash的变量
2.1、什么是bash变量
变量是shell 传递数据的一种方法。变量是用来代表每个值的符号名。我们可以把变量当成一个容器,脚本可以在内存中存储数据,然后通过变量。就可以在脚本执行中进行修改和访问存储的数据
2.2、变量的语法
name=values
values的类型一般有如下几种:
1)字符串:name=root
2)引用变量: name="$PATH"
3)命令引用: name=`COMMAND` 或者name=$(COMMAND)
变量引用
echo $NAME
强引用和弱引用
"$name" 弱引用其中的变量名会被替换成变量的值
'$name' 强引用其中的变量名不会被替换成变量的值,而保持其原本的字符串
2.3、 变量的命名规则
1)、 变量名称通常是大写字母,它可以由数字
、字母(大小写)
和下划线
组成。但是要注意变量名称不能以数字
、特殊字符
开头
[root@myx01~]$ name1=zhangsan
[root@myx01~]$ 1name=zhangsan
-bash: 1name=zhangsan: 未找到命令
[root@myx01~]$ _name2=zhangsan
2)、 等号 = 用于为变量分配值,在使用过程中等号两边不能有空格
[root@myx01~]$ name = zhangsan
-bash: name: 未找到命令
[root@myx01~]$ name= zhangsan
-bash: zhangsan: 未找到命令
[root@myx01~]$ name =zhangsan
-bash: name: 未找到命令
3)、 变量存储的数据类型是整数值和字符串值,但是整数型也会被定义为字符串型
[root@myx01~]$ a=100
[root@myx01~]$ b=200
[root@myx01~]$ c=$a+$b
[root@myx01~]$ echo $c
100+200
4)、 在对变量赋于字符串值时,如果字符串中存在空格,需要使用单引号或双引号把它引起来
[root@myx01~]$ city='wu han'
[root@myx01~]$ city="wu han"
[root@myx01~]$ city=wu han
-bash: han: 未找到命令
5)、 要对变量进行调用,可以在变量名称前加美元符号$
[root@myx01~]$ echo $city
wu han
6)、 如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含“$变量名”或用${变量名}添加的内容
[root@myx01~]$ echo ${city} ni hao! #方法一
wu han ni hao!
[root@myx01~]$ echo "$city" ni hao! #方法二
wu han ni hao!
7)、变量命名时要注意“见名知义”,一目了然,能体现出实际的含义
[root@myx01~]$ mem_monitor=$(free -m | grep -i mem)
[root@myx01~]$ echo $mem_monitor
Mem: 1819 188 1452 9 178 1476
8)、变量命名时变量名称最好采用驼峰体,小驼峰studentName,大驼峰StudentName
[root@myx01~]$ Mem_Monitor=$(free -m |grep -i mem)
[root@myx01~]$ echo $Mem_Monitor
Mem: 1819 188 1452 9 178 1476
9)、不要使用系统中保留的关键字:if
,for
,else,exit
,continue
等
2.4、BASE SHELL的扩展功能
我们最常见的就是扩展变量值和命令替换和算术扩展:
1)、 $name
是${name}
的简化版本,但是在某些情况下,还必须使用花括号引起的方式来消除歧义并避免意外的结果
2)、 命令的替换就是将命令的调用替换为执行命令后的结果的输出,它的使用方式:我们将命令括在``
中 旧形式来调用命令结果,(新形式)是使用$()
语法
3)、 在命令替换中,使用新语法$(),它允许进行嵌套命令替换
示例1:变量中的“_”
[root@myx01~]$ name=mengyaunxi
[root@myx01~]$ age=20
[root@myx01~]$ echo $name$age
mengyaunxi20
[root@myx01~]$ echo $name_$age ##因为“_”可以作为变量名,系统误认为$name_也是一个变量名,会出现错误的结果
20
[root@myx01~]$ echo ${name}_$age ##必须要花括号来进行消除歧义
mengyaunxi_20
[root@myx01~]$ echo ${name}_${age}
mengyaunxi_20
示例2:将命令的结果赋值给变量
[root@myx01/tmp]$ swap=`free -h | grep -i swap`
[root@myx01/tmp]$ echo $swap
Swap: 2.0G 0B 2.0G
##添加压缩文件
[root@myx01~]$ mkdir {1..5}.txt
[root@myx01~]$ var1=$(tar cvf /tmp/a.tar $(find /root -name "*.txt"))
tar: Removing leading `/' from member names
[root@myx01~]$ echo $var1
/root/1.txt/ /root/2.txt/ /root/3.txt/ /root/4.txt/ /root/5.txt/
示例3:将SWAP内存内存传递给变量
[root@myx01~]$ swap=`free -h | grep -i swap`
[root@myx01~]$ echo $swap
Swap: 2.0G 0B 2.0G
[root@myx01~]$ swap=$(free -h|grep -i swap)
[root@myx01~]$ echo $swap
Swap: 2.0G 0B 2.0G
示例4:变量切割
[root@myx01~]$ num=123456
[root@myx01~]$ echo ${num:2:3} # 2:第三位(1是第零位,2是第一位以此类推) 3:往后截取的位数
345
[root@myx01~]$ echo ${num:2}
3456
[root@myx01~]$ echo ${num:2:-1} # -1 取最后一个值
345
4)、进行算术扩展时使用$[]
进行,同时它也允许算术替换
[root@myx01~]$ num1=20
[root@myx01~]$ num2=5
[root@myx01~]$ echo $[ $num1 / $num2 ]
4
[root@myx01~]$ echo $[ $num1 % $num2 ]
0
[root@myx01~]$ echo $[ $num1 - $num2 ]
15
[root@myx01~]$ echo $[ $num1 + $num2 ]
25
[root@myx01~]$ echo $[ $num1 * $num2 ]
100
[root@myx01~]$ echo $[ $num1 ** $num2 ]
3200000
2.5、变量类型
1)、用户自定义变量:用户自定义的变量,仅本地有效,其他进程及当前进程的子进程无效。
2)、环境变量:这种变量中主要保存的是和系统操作环境相关的数据。
3)、位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
4)、预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
2.5.1 用户自定义变量
由字母或下划线打头,不允许数字开头,后面由字母、数字或下划线组成,并且大小写字母意义不同。变量名长度没有限制。
使用变量值时,要在变量名前加上前缀“$”。
2.5.1.1 定义自定义变量
示例:创建一个自定义变量
[root@myx01~]$ name=myx
示例:在对变量赋值时,可以引用系统变量
[root@myx01~]$ name="$PATH"
[root@myx01~]$ echo $name
/usr/local/node/bin/:/apps/tree/bin:/apps/httpd/bin:/apps/cmatrix/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
2.5.1.2 查询变量 set
、env
注意:env查看不到自定义的变量(只能查看当前用户环境变量),set可以查看当前用户的所有的变量
[root@myx01~]$ set | grep myx
HOSTNAME=myx01
name=myx
[root@myx01~]$ env | grep myx
HOSTNAME=myx01
语法:set [变量名]
-u:当查看一个不存在的变量的时候直接反馈 “变量不存在”
-x: 如果设置此选项,在命令执行之前,会先把命令输出一次
-e: 如果语法执行有问题,则停止执行
示例:
[root@myx01~]$ echo $abc ##未设置-u参数之前
[root@myx01~]$ a="bcd"
[root@myx01~]$ echo $a
bcd
[root@myx01~]$ set -u ##设置-u参数之后
[root@myx01~]$ echo $bcd
-bash: aaa: unbound variable
[root@myx01~]$ echo $a
bcd
2.5.1.3 删除变量
语法:unset [变量名]
[root@myx01~]$ name=MYX
[root@myx01~]$ set | grep MYX
name=MYX
[root@myx01~]$ unset name
[root@myx01~]$ set | grep MYX
也可以一次性删除多个变量
[root@myx01~]$ unset name title ##同时删除name,title变量
[root@myx01~]$ echo $name $title
注意:变量是临时存放在内存中的,当终端退出后,变量会被删除,定义好的变量无法跨终端查看
2.5.2 环境变量
环境变量:用户自定义环境变量和系统环境变量
用户自定义环境变量和用户定义变量的区别:
1)“用户自定义环境变量” 可以在当前终端和子shell中生效 ,切换终端会失效
临时:export NAME=VALUES
永久:/etc/profile,/etc/bashrc/.bashrc
2)“用户自定义变量” 只能在当前shell中生效
语法:NAME=VALUES
查看进程
[root@myx01~]$ pstree -p
结论:用户自定义变量
只能在当前自己的bash环境中运行,无法跨bash执行。如果想让子shell能执行父shell的变量,必须要将变量定义为自定义环境变量
,反过来,父shell无法继承子shell的变量的值。
2.5.2.2 系统环境变量
bash中常见的内建环境变量:
PATH
SHELL
USER
UID
HOME
PWD
SHLVL ##shell锲套的层数
LANG
MAIL
HOSTNAME
HISTSIZE
_ ##表示上一个命令的最后一个参数
##查看系统环境变量
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
2.5.2.3 PS1环境变量
命令提示符设置
在Linux中,PS1是一个全局变量,查看PS1的格式如
[root@localhost ~]# echo $PS1
[\u@\h \W]\$
1**)设置PS1变量的格式**
PS1='[\u@\h \w]\$ '
----注意$后面有一个空格!如果没有空格的话,将会报错!
\d :代表日期,格式为weekday month date,例如:"Mon Aug 1"
\H :完整的主机名称。例如:我的机器名称为:akesu.linux,则这个名称就是akesu.linux
\h :仅取主机的第一个名字,如上例,则为akesu,.linux则被省略
\t :显示时间为24小时格式,如:HH:MM:SS
\T :显示时间为12小时格式
\A :显示时间为24小时格式:HH:MM
\u :当前用户的账号名称
\v :BASH的版本信息
\w :完整的工作目录名称。家目录会以 ~代替
\W :利用basename取得工作目录名称,所以只会列出最后一个目录
\# :下达的第几个命令
\$ :提示字符,如果是root时,提示符为:# ,普通用户则为:$
[root@localhost:w 20:18:09]$ PS1='[\u@\h:\w \t]$ '
以上设置均时临时生效,需要永久生效需要写入/etc/bashrc
文件中。
2.5.2.4 lang变量
用于系统使用的语言
[root@localhost:/etc 20:22:21]$ echo $LANG
en_US.UTF-8
[root@localhost:/etc 20:24:17]$ locale -a --查看系统中支持的语言
[root@localhost:/etc 20:24:17]$ locale --查看当前安装的语言
[root@localhost:/etc 20:23:04]$ LANG=zh_CN_UTF-8 --设置当前的语序
[root@localhost:/etc 20:23:29]$ echo $LANG
zh_CN_UTF-8
可以通过在/etc/locale.conf
这个文件查看当前系统的默认语系,可以进行修改。
vi /etc/locale.conf
LANG="zh_CN.UTF-8"
# LANG="en_US.UTF-8"
2.6 位置参数变量
Shell解释执行用户的命令时,将命令行的第一个字作为命令名,而其它字作为参数。由出现在命令行上的位置确定的参数称为位置参数。
使用$N 来表示
$n:n 为数字,$0 代表命令本身,$1-$9 代表第一到第九个参数,十以上的参数需要用大括号包含,如 ${10}。
$ *:这个变量代表命令行中所有的参数,$* 把所有的参数看成一个整体。
$* 11 22 33 44 # $* 作为一个整体输出
$@:这个变量也代表命令行中所有的参数,不过 $@ 把每个参数区分对待。
$@ 11 # $@将每个参数单独输出
22
33
44
$#:这个变量代表命令行中所有参数的个数。
$# 4
set -- ##清除所有的位置参数
案例:位置参数应用于文件管理
#!/bin/bash
WARNNING_COLOR="echo -e \e[1;31m" ##定义告警颜色
END="\e[0m"
DIR=/tmp/`date +%F_%H-%M-%S` ##定义临时目录位置
mkdir $DIR ##创建临时目录
mv $1 $DIR ##移动文件到临时目录
${WARNNING_COLOR}move $1 to $DIR $END ##打印移动文件内容信息
[root@localhost shells]# alias rm=/data/shells/rm.sh ##定义别名
测试:
[root@localhost ~]# touch a
[root@localhost ~]# rm a
move a to /tmp/2022-08-12_21-15-39
注意:如果想同时删除多个文件,将位置参数 $1 修改成 $*
,即可表示所有的位置参数。
面试扩展题:鸡兔同笼问题:笼子里有30只头,68只脚,兔多少?鸡多少?
#!/bin/bash
#Description: The test script
#QQ: 2041598918
#Author: mengyuanxi
#email: 2041598918@qq.com
#FileName: jitutonglong.sh
#Date: 2023-10-07
#=======================================================
read -p "头数:" TOU
read -p "脚数:" JIAO
# 头数和脚数的总和
total_heads=TOU
total_legs=JIAO
# 鸡和兔的脚数
chicken_legs=2
rabbit_legs=4
# 鸡和兔的数量设为未知数
chicken_count=0
rabbit_count=0
# 通过方程求解计算兔的数量
rabbit_count=$(( (total_legs - 2 * total_heads) / 2 ))
# 计算鸡的数量
chicken_count=$(( total_heads - rabbit_count ))
# 输出结果
echo "鸡的数量: $chicken_count"
echo "兔的数量: $rabbit_count"
2.7 特殊变量
符号 | 作用 | |
---|---|---|
$? | 显示最后命令的退出状态;0表示没有错误,其他任何值表明有错误 :1-255 | exit 100 # 自定义状态码 |
$! | 后台运行的最后一个进程的进程号pid | echo $! |
$$ | 当前进程的进程号PID | echo $$ |
2.8 只读变量
只读变量的定义方法:
readonly [name]
declare -r [name]
示例:
[root@localhost ~]# readonly a=100
[root@localhost ~]# a=20
-bash: a: 只读变量
[root@localhost ~]# declare -r b=200
[root@localhost ~]# b=300
-bash: b: 只读变量
2.9 read接收键盘输入
语法:
[root@localhost ~]# read [选项] [变量名]
选项:
-p "提示信息" 在等待read输入时,输出提示信息
-t 秒数 read命令会一直等待用户的输入,使用此选项可以指定等待的时间
-n 字符数 read 命令只接受指定的字符数
-s 隐藏字符
扩展面试题:为什么使用echo获取不到值?
[root@localhost ~]# cat a.txt
1 2
[root@localhost ~]# read x y <a.txt ; echo x=$x y=$y
x=1 y=2
[root@localhost ~]# echo 1 2 |read x y ;echo $x $y ##没有结果
[root@localhost ~]# echo 1 2 |(read x y ;echo $x $y) ##在子shell中,每一个命令都被管道当成一个独立的进程进行来执行,
1 2
三、全局环境变量
环境变量的配置文件主要有5类:
1、全局配置文件:
/etc/profile:为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,并从指定目录中(通常为/etc/profile.d)的配置文件中搜集shell的设置
/etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被执行
2、用户配置文件:
~/.bash_profile:用户使用该文件设定专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件
~/.bashrc:该文件包含专用于用户的bash shell的bash信息,当登录时以及每次打开新的shell时,该文件被读取
~/.bash_logout:当每次退出系统(退出bash shell)时,执行该文件
3.1 环境变量详细加载过程
常用的环境变量
变量名称 | 作用 |
---|---|
HOME | 用户的主目录(即家目录) |
SHELL | 用户在使用的Shell解释器名称 |
HISTSIZE | 输出的历史命令记录条数 |
HISTFILESIZE | 保存的历史命令记录条数 |
邮件保存路径 | |
LANG | 系统语言、语系名称 |
RANDOM | 生成一个随机数字 |
PS1 | Bash解释器的提示符 |
PATH | 定义解释器搜索用户执行命令的路径 |
EDITOR | 用户默认的文本编辑器 |
3.1.2 环境变量
1、 用户环境变量
(1).bash_profile
:定义了用户的个人化路径与环境变量的文件名称。
(2).bashrc
:该文件包含专用于你的shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取。
(3).bash_history
:记录命令历史用的。
(4).bash_logout
:当退出shell时,会执行该文件。可以把一些清理的工作放到这个文件中。
四、用户登录提示信息设置
4.1、 shell登陆信息 /etc/issue
常见的几个选项
\d 显示当前日期; date
\l 显示虚拟控制台号;
\m 显示机器类型,即 CPU 架构,如 i386 或 x86_64 等(相当于 uname -m);
\n 显示主机的网络名(相当于 uname -n);
\o 显示域名;
\r 显示 Kernel 内核版本号(相当于 uname -r);
\t 显示当前时间;
\s 显示当前操作系统名称;
\u 显示当前登录用户的编号,\U 显示当前登录用户的编号和用户;
\v 显示当前操作系统的版本日期;
4.2、 ssh 输入用户名后欢迎信息设置/etc/ssh/sshd_config
当前输入用户后,并没有显示任何欢迎信息,而是直接弹出输入密码提示。
vim /etc/ssh/sshd_config
touch /etc/ssh/Banner
echo "welcome to MYX" >/etc/ssh/Banner
systemctl restart sshd
4.3、 ssh 输入密码后欢迎信息设置/etc/motd
1)可以修改 /etc/motd 文件,定义 ssh 成功登录后的欢迎信息。
- 感谢你赐予我前进的力量