「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

你必须非常努力,才能看起来毫不费力!

微信搜索公众号[ 漫漫Coding路 ],一起From Zero To Hero !

前言

与 Java、Go 等编程语言类似,Bash 中也可以自定义变量,那么如何自定义变量呢?除了自定义变量之外,Bash中还有没有其他类型的变量供我们使用呢?一起来学习吧!

变量分类

Bash 中,变量主要分为以下四种类型:

  • 自定义变量:类似Java、Go语言中的自定义变量,灵活性最高;
  • 环境变量:主要保存和系统环境相关的变量,系统已经定义好了很多环境变量,同时允许用户新增自定义环境变量,灵活性较高;
  • 位置参数变量:这种变量主要是用来向脚本中传递参数或者数据用的,参数名不能自定义,变量的作用也是固定的,只能更改值;
  • 预定义变量:Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。

由于内容较多,我们分为两篇文章来学习,本篇文章主要学习前两种变量:自定义变量和环境变量。

自定义变量

Java 中,你可以使用类似 int i = 1 的形式定义一个变量,同样在 Bash 中,你也可以定义变量,需要遵循以下几点规则:

  • 变量名可以由字母、数字、下划线组成,但是不能以数字开头
  • 变量与值之间通过 = 连接,中间不能有空格
  • 变量的值如果有空格,需要用单引号或者双引号包括
  • 在变量的值中,可以使用 "\" 符号进行转义
  • 如果需要追加变量的值,需要使用双引号包含"$变量名" 或者 ${变量名包含}
  • Bash定义的变量默认都是字符串类型的,如果要进行数值运算,必须指定变量类型为数值类型

用户变量也可以称为本地变量,因为自定义变量只在当前 Shell 中生效,其他 Shell 不能使用。

示例

# 变量与值通过 '=' 连接[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 $titlethis is a title# 变量的值可以使用转义符进行转义[root@VM-0-5-centos ~]# name=\lifelmy[root@VM-0-5-centos ~]# echo $namelifelmy[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 $name1lifelmy123[root@VM-0-5-centos ~]# echo $name2lifelmy456# 命令的结果赋值给变量[root@VM-0-5-centos ~]# now=$(date)[root@VM-0-5-centos ~]# echo $now2021年 11月 14日 星期日 13:48:43 CST复制代码

变量调用

使用 $变量名 可以调用变量

[root@VM-0-5-centos ~]# name=lifelmy[root@VM-0-5-centos ~]# echo $namelifelmy复制代码

变量查看

使用 set 命令可以查看所有变量(包括环境变量)

[root@VM-0-5-centos ~]# set | grep name_name=lifelmyname=lifelmyname1=lifelmy123name2=lifelmy456复制代码

变量删除

使用 unset 可以删除变量

[root@VM-0-5-centos ~]# name=lifelmy[root@VM-0-5-centos ~]# echo $namelifelmy[root@VM-0-5-centos ~]# unset name[root@VM-0-5-centos ~]# echo $name复制代码

数值运算

自定义变量的类型默认是字符串类型,无法进行数值计算:

[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 $cc1+2复制代码

那么如何进行数值运算呢?在介绍之前,我们先来学习一个命令,该命令用于查看、设置变量的类型:

declare [+/-] [选项] 变量名选项:-: 给变量设定属性类型+: 取消变量的类型属性-i: 将变量声明为整数型(integer)-x: 将变量声明为环境变量-p: 显示指定变量被声明的类型复制代码

declare示例

[root@VM-0-5-centos ~]# name=lifelmy# 默认是字符串类型[root@VM-0-5-centos ~]# declare -p namedeclare -- name="lifelmy"# 声明为环境变量后,再次查看变成了 -x[root@VM-0-5-centos ~]# export name[root@VM-0-5-centos ~]# declare -p namedeclare -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 agedeclare -i age="18"复制代码

接下来我们介绍三种数值计算的方法:

  1. 使用 declare 声明
[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 $c23复制代码
  1. 使用 exprlet 运算工具
[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 $d2复制代码
  1. 使用运算式

使用 $((运算式))$[运算式]

# $((运算式))  或 $[运算式][root@9c12e0d24857 /]# a=2[root@9c12e0d24857 /]# b=3[root@9c12e0d24857 /]# c=$(($a+$b))[root@9c12e0d24857 /]# echo $c5[root@9c12e0d24857 /]# d=$[$a+$b][root@9c12e0d24857 /]# echo $d5复制代码

在实际使用中,最常用的是第三种方式。

环境变量

前面讨论的自定义变量,只会在 当前Shell 中生效,而环境变量会在 当前Shell 以及这个 Shell 的所有 子Shell 中生效。如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的 Shell 中生效。

什么叫做 子Shell 呢? 我们在 Shell 编程初体验 查看支持的Shell 章节讨论过,可以通过执行命令切换到其他 Shell 中,那么当前 Shell 就是 父Shell,切换后的 Shell 就是 子Shell

设置环境变量

export 变量名=变量值复制代码

如果变量已经存在,可直接使用 export 声明

export 变量名复制代码

查询环境变量

env复制代码

删除环境变量

unset 变量名复制代码

使用环境变量

和自定义变量类似,使用 $变量名 取值

echo $变量名复制代码

示例一

创建并通过进程树查看 子Shell

# 1. 在当前Bash中执行该命令,能够找到如下输出的一条链路[root@VM-0-5-centos ~]# pstreesystemd──sshd──sshd───bash───pstree# 2. 然后在当前Bash中开启一个新的Bash,即一个子Shell#    再查看进程树相应链路,发现多了个bash[root@VM-0-5-centos ~]# bash[root@VM-0-5-centos ~]# pstreesystemd─sshd─┬─sshd───bash───bash───pstree# 3. 退出子Shell,查看进程树,发现子Shell没有了[root@VM-0-5-centos ~]# exitexit[root@VM-0-5-centos ~]# pstreesystemd──sshd──sshd───bash───pstree复制代码

示例二

设置环境变量

# 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复制代码

示例三

查看、使用、删除环境变量

# 使用 env 命令查看环境变量[root@VM-0-5-centos ~]# envgender=maleage=18SHELL=/bin/bashPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin......# 使用环境变量[root@VM-0-5-centos ~]# echo $age18[root@VM-0-5-centos ~]# echo $gendermale# 删除环境变量[root@VM-0-5-centos ~]# unset age复制代码

常见系统环境变量-PATH

PATH下面的内容,是系统用于查找命令的路径(使用":"分隔)

[root@VM-0-5-centos ~]# env | grep PATHPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin复制代码

我们可以在PATH后,按照规定的格式,追加自定义的文件夹

PATH="$PATH":/root/hello复制代码

Shell 编程初体验 编写第一个Shell脚本 章节介绍过,想要执行脚本,必须使用相对路径或者绝对路径。对于 Linux 中的这些系统命令,例如 ls、cd、mkdir,和我们自己写的脚本文件一样,也是可执行程序,为什么输入这些命令时,不需要使用相对或绝对路径呢?那是因为当我们输入了一个命令后,Linux 会在 PATH 下所有文件夹中寻找这个可执行程序,如果找到了就可以执行,如果找不到就会报错 "未找到命令",这里的未找到,就是在 PATH 对应的路径中未找到。

比如我们写一个脚本,输出 "hello world",默认只能使用相对或绝对路径执行。

[root@VM-0-5-centos ~]# vim hello.sh#!/bin/bashecho "hello world"[root@VM-0-5-centos ~]# chmod 755 hello.sh# 相对路径[root@VM-0-5-centos ~]# ./hello.shhello world# 绝对路径[root@VM-0-5-centos ~]# /root/hello.shhello world复制代码

但是如果我们把该脚本添加到 PATH 下面的一个文件夹中,就可以直接使用了,同时按 "TAB" 键也会进行补全! 可见 "TAB" 键也是在 PATH 下面的路径中查找的!

[root@VM-0-5-centos ~]# cp hello.sh /sbin/[root@VM-0-5-centos ~]# hello.shhello world复制代码

但是我们并不推荐使用这种方式,因为 "/sbin" 目录就是用来保存系统命令的,把我们自定义的命令脚本放进去,会将文件搞混。而更优雅的方式,则是将我们脚本所在的文件夹,追加到 PATH 中。

# 1. 删除上一步复制的hello.sh[root@VM-0-5-centos ~]# rm /sbin/hello.shrm:是否删除普通文件 "/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.shhello world复制代码

以上的改动只会在当前Shell以及子Shell中生效,因为我们暂未将其写入环境变量配置文件中去。

常见系统环境变量-PS1

定义系统提示符的变量,就是我们输入命令前的提示符,当前我的就是 [root@VM-0-5-centos ~]

PS1 也是属于环境变量的一种,但是使用 env 命令查询不到,使用 set 可以查找到

[root@VM-0-5-centos ~]# set | grep PS1PS1='[\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的值来看下效果:

[root@VM-0-5-centos ~]# PS1='[\u@ \t \W]\$ '[root@ 15:47:59 ~]# lshello.sh复制代码

这种改动也是只是临时生效,需要永久生效需要写入配置文件。当然这里只是体验下,系统默认的已经够用了,其实也无需更改。

总结

本篇文章介绍了Bash 中的变量分类:自定义变量、环境变量、位置参数变量和预定义变量,并详细介绍了前两种:

  1. 自定义变量的定义、查看、调用以及如何进行数值计算;
  2. 环境变量的设置、查看、使用,并介绍了两种常见的环境变量:PATH 和 PS1。

更多

个人博客: lifelmy.github.io/

微信公众号:漫漫Coding路