前言
与 Java、Go 等编程语言类似,Bash 中也可以自定义变量,那么如何自定义变量呢?除了自定义变量之外,Bash中还有没有其他类型的变量供我们使用呢?一起来学习吧!
变量分类
在 Bash
中,变量主要分为以下四种类型:
- 自定义变量:类似Java、Go语言中的自定义变量,灵活性最高;
- 环境变量:主要保存和系统环境相关的变量,系统已经定义好了很多环境变量,同时允许用户新增自定义环境变量,灵活性较高;
- 位置参数变量:这种变量主要是用来向脚本中传递参数或者数据用的,参数名不能自定义,变量的作用也是固定的,只能更改值;
- 预定义变量:Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
由于内容较多,我们分为两篇文章来学习,本篇文章主要学习前两种变量:自定义变量和环境变量。
自定义变量
在 Java
中,你可以使用类似 int i = 1
的形式定义一个变量,同样在 Bash
中,你也可以定义变量,需要遵循以下几点规则:
- 变量名可以由字母、数字、下划线组成,但是不能以数字开头
- 变量与值之间通过
=
连接,中间不能有空格
- 变量的值如果有空格,需要用单引号或者双引号包括
- 在变量的值中,可以使用 “\” 符号进行转义
- 如果需要追加变量的值,需要使用双引号包含"$变量名" 或者 ${变量名包含}
- Bash定义的变量默认都是字符串类型的,如果要进行数值运算,必须指定变量类型为数值类型
用户变量也可以称为本地变量,因为自定义变量只在当前 Shell 中生效,其他 Shell 不能使用。
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# 变量与值通过 '=' 连接
[root@VM-0-5-centos ~]# name=lifelmy
# 变量与值中间不能有空格
[root@VM-0-5-centos ~]# name = lifelmy
-bash: name: 未找到命令
# 变量名不能使用数字开头,
[root@VM-0-5-centos ~]# 2name=lifelmy
-bash: 2name=lifelmy: 未找到命令
# 值如果有空格,需要使用单引号或者双引号包括
[root@VM-0-5-centos ~]# title=this is a title
-bash: is: 未找到命令
[root@VM-0-5-centos ~]# title="this is a title"
[root@VM-0-5-centos ~]# echo $title
this is a title
# 变量的值可以使用转义符进行转义
[root@VM-0-5-centos ~]# name=\lifelmy
[root@VM-0-5-centos ~]# echo $name
lifelmy
[root@VM-0-5-centos ~]# name=\\lifelmy
[root@VM-0-5-centos ~]# echo $name
\lifelmy
# 变量值的追加
[root@VM-0-5-centos ~]# name=lifelmy
[root@VM-0-5-centos ~]# name1=${name}123
[root@VM-0-5-centos ~]# name2="$name"456
[root@VM-0-5-centos ~]# echo $name1
lifelmy123
[root@VM-0-5-centos ~]# echo $name2
lifelmy456
# 命令的结果赋值给变量
[root@VM-0-5-centos ~]# now=$(date)
[root@VM-0-5-centos ~]# echo $now
2021年 11月 14日 星期日 13:48:43 CST
|
变量调用
使用 $变量名
可以调用变量
1
2
3
|
[root@VM-0-5-centos ~]# name=lifelmy
[root@VM-0-5-centos ~]# echo $name
lifelmy
|
变量查看
使用 set
命令可以查看所有变量(包括环境变量)
1
2
3
4
5
|
[root@VM-0-5-centos ~]# set | grep name
_name=lifelmy
name=lifelmy
name1=lifelmy123
name2=lifelmy456
|
变量删除
使用 unset
可以删除变量
1
2
3
4
5
6
7
|
[root@VM-0-5-centos ~]# name=lifelmy
[root@VM-0-5-centos ~]# echo $name
lifelmy
[root@VM-0-5-centos ~]# unset name
[root@VM-0-5-centos ~]# echo $name
|
数值运算
自定义变量的类型默认是字符串类型,无法进行数值计算:
1
2
3
4
5
|
[root@VM-0-5-centos ~]# aa=1
[root@VM-0-5-centos ~]# bb=2
[root@VM-0-5-centos ~]# cc=$aa+$bb
[root@VM-0-5-centos ~]# echo $cc
1+2
|
那么如何进行数值运算呢?在介绍之前,我们先来学习一个命令,该命令用于查看、设置变量的类型:
1
2
3
4
5
6
7
8
|
declare [+/-] [选项] 变量名
选项:
-: 给变量设定属性类型
+: 取消变量的类型属性
-i: 将变量声明为整数型(integer)
-x: 将变量声明为环境变量
-p: 显示指定变量被声明的类型
|
declare示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@VM-0-5-centos ~]# name=lifelmy
# 默认是字符串类型
[root@VM-0-5-centos ~]# declare -p name
declare -- name="lifelmy"
# 声明为环境变量后,再次查看变成了 -x
[root@VM-0-5-centos ~]# export name
[root@VM-0-5-centos ~]# declare -p name
declare -x name="lifelmy"
# 声明为整数类型
[root@VM-0-5-centos ~]# declare -i age
[root@VM-0-5-centos ~]# age=18
[root@VM-0-5-centos ~]# declare -p age
declare -i age="18"
|
接下来我们介绍三种数值计算的方法:
- 使用
declare
声明
1
2
3
4
5
6
7
8
|
[root@VM-0-5-centos ~]# a=11
[root@VM-0-5-centos ~]# b=12
# 声明c为整数
[root@VM-0-5-centos ~]# declare -i c
[root@VM-0-5-centos ~]# c=$a+$b
[root@VM-0-5-centos ~]# echo $c
23
|
- 使用
expr
或 let
运算工具
1
2
3
4
5
6
7
8
9
10
11
|
[root@VM-0-5-centos ~]# a=1
[root@VM-0-5-centos ~]# b=2
# 注意:'+'号左右两侧必须有空格
[root@VM-0-5-centos ~]# c=$(expr $a + $b)
[root@VM-0-5-centos ~]# echo $c
# 不需要有空格
[root@VM-0-5-centos ~]# let d=$a*$b
[root@VM-0-5-centos ~]# echo $d
2
|
- 使用运算式
使用 $((运算式))
或 $[运算式]
1
2
3
4
5
6
7
8
9
10
|
# $((运算式)) 或 $[运算式]
[root@9c12e0d24857 /]# a=2
[root@9c12e0d24857 /]# b=3
[root@9c12e0d24857 /]# c=$(($a+$b))
[root@9c12e0d24857 /]# echo $c
5
[root@9c12e0d24857 /]# d=$[$a+$b]
[root@9c12e0d24857 /]# echo $d
5
|
在实际使用中,最常用的是第三种方式。
环境变量
前面讨论的自定义变量,只会在 当前Shell
中生效,而环境变量会在 当前Shell
以及这个 Shell 的所有 子Shell
中生效。如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的 Shell 中生效。
什么叫做 子Shell 呢? 我们在 Shell 编程初体验 查看支持的Shell 章节讨论过,可以通过执行命令切换到其他 Shell 中,那么当前 Shell 就是 父Shell
,切换后的 Shell 就是 子Shell
。
设置环境变量
如果变量已经存在,可直接使用 export
声明
查询环境变量
删除环境变量
使用环境变量
和自定义变量类似,使用 $变量名
取值
示例一
创建并通过进程树查看 子Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 1. 在当前Bash中执行该命令,能够找到如下输出的一条链路
[root@VM-0-5-centos ~]# pstree
systemd──sshd──sshd───bash───pstree
# 2. 然后在当前Bash中开启一个新的Bash,即一个子Shell
# 再查看进程树相应链路,发现多了个bash
[root@VM-0-5-centos ~]# bash
[root@VM-0-5-centos ~]# pstree
systemd─sshd─┬─sshd───bash───bash───pstree
# 3. 退出子Shell,查看进程树,发现子Shell没有了
[root@VM-0-5-centos ~]# exit
exit
[root@VM-0-5-centos ~]# pstree
systemd──sshd──sshd───bash───pstree
|
示例二
设置环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 1. 设置了一个自定义变量,并通过两种方式设置了两个环境变量age 和 gender
[root@VM-0-5-centos ~]# name=lifelmy
[root@VM-0-5-centos ~]# age=18
[root@VM-0-5-centos ~]# export gender=male
[root@VM-0-5-centos ~]# export age
# 2. 通过 set 命令查看所有变量,都可以查到
[root@VM-0-5-centos ~]# set | grep name=
name=lifelmy
[root@VM-0-5-centos ~]# set | grep age=
age=18
[root@VM-0-5-centos ~]# set | grep gender=
gender=male
# 3. 进入一个 子Shell
[root@VM-0-5-centos ~]# bash
# 4. 发现只有两个环境变量,可以在子Shell中可以查询到
[root@VM-0-5-centos ~]# set | grep name=
[root@VM-0-5-centos ~]# set | grep age=
age=18
[root@VM-0-5-centos ~]# set | grep gender=
gender=male
|
示例三
查看、使用、删除环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 使用 env 命令查看环境变量
[root@VM-0-5-centos ~]# env
gender=male
age=18
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
......
# 使用环境变量
[root@VM-0-5-centos ~]# echo $age
18
[root@VM-0-5-centos ~]# echo $gender
male
# 删除环境变量
[root@VM-0-5-centos ~]# unset age
|
常见系统环境变量-PATH
PATH下面的内容,是系统用于查找命令的路径(使用":“分隔)
1
2
|
[root@VM-0-5-centos ~]# env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
|
我们可以在PATH后,按照规定的格式,追加自定义的文件夹
1
|
PATH="$PATH":/root/hello
|
Shell 编程初体验 编写第一个Shell脚本 章节介绍过,想要执行脚本,必须使用相对路径或者绝对路径。对于 Linux 中的这些系统命令,例如 ls、cd、mkdir,和我们自己写的脚本文件一样,也是可执行程序,为什么输入这些命令时,不需要使用相对或绝对路径呢?那是因为当我们输入了一个命令后,Linux 会在 PATH 下所有文件夹中寻找这个可执行程序,如果找到了就可以执行,如果找不到就会报错 “未找到命令”,这里的未找到,就是在 PATH 对应的路径中未找到。
比如我们写一个脚本,输出 “hello world”,默认只能使用相对或绝对路径执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@VM-0-5-centos ~]# vim hello.sh
#!/bin/bash
echo "hello world"
[root@VM-0-5-centos ~]# chmod 755 hello.sh
# 相对路径
[root@VM-0-5-centos ~]# ./hello.sh
hello world
# 绝对路径
[root@VM-0-5-centos ~]# /root/hello.sh
hello world
|
但是如果我们把该脚本添加到 PATH
下面的一个文件夹中,就可以直接使用了!同时按 “TAB” 键也会进行补全! 可见 “TAB” 键也是在 PATH 下面的路径中查找的!
1
2
3
|
[root@VM-0-5-centos ~]# cp hello.sh /sbin/
[root@VM-0-5-centos ~]# hello.sh
hello world
|
但是我们并不推荐使用这种方式,因为 “/sbin” 目录就是用来保存系统命令的,把我们自定义的命令脚本放进去,会将文件搞混。而更优雅的方式,则是将我们脚本所在的文件夹,追加到 PATH 中。
1
2
3
4
5
6
7
8
9
10
|
# 1. 删除上一步复制的hello.sh
[root@VM-0-5-centos ~]# rm /sbin/hello.sh
rm:是否删除普通文件 "/sbin/hello.sh"?y
# 将当前脚本文件所在目录,添加到 PATH 中
[root@VM-0-5-centos ~]# PATH="$PATH":/root
[root@VM-0-5-centos ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root
[root@VM-0-5-centos ~]# hello.sh
hello world
|
以上的改动只会在当前Shell以及子Shell中生效,因为我们暂未将其写入环境变量配置文件中去。
常见系统环境变量-PS1
定义系统提示符的变量,就是我们输入命令前的提示符,当前我的就是 [root@VM-0-5-centos ~]
PS1 也是属于环境变量的一种,但是使用 env
命令查询不到,使用 set
可以查找到
1
2
|
[root@VM-0-5-centos ~]# set | grep PS1
PS1='[\u@\h \W]\$ '
|
代码 |
说明 |
\d |
显示日期,格式为 “星期 月 日” |
\h |
显示简写主机名,如默认主机名为"localhost” |
\t |
显示24小时制事件,格式为"HH:MM:SS" |
\T |
显示12小时制事件,格式为"HH:MM:SS" |
\A |
显示24小时制事件,格式为"HH:MM" |
\u |
显示当前用户名 |
\w |
显示当前所在目录的完整名称 |
\W |
显示当前所在目录的最后一个目录 |
\# |
执行的第几个命令 |
\$ |
提示符,如果是root用户显示"#",普通用户提示符为"$" |
我们可以改动下PS1的值来看下效果:
1
2
3
|
[root@VM-0-5-centos ~]# PS1='[\u@ \t \W]\$ '
[root@ 15:47:59 ~]# ls
hello.sh
|
这种改动也是只是临时生效,需要永久生效需要写入配置文件。当然这里只是体验下,系统默认的已经够用了,其实也无需更改。
总结
本篇文章介绍了Bash 中的变量分类:自定义变量、环境变量、位置参数变量和预定义变量,并详细介绍了前两种:
- 自定义变量的定义、查看、调用以及如何进行数值计算;
- 环境变量的设置、查看、使用,并介绍了两种常见的环境变量:PATH 和 PS1。
更多
微信公众号:CodePlayer