Shell编程系列(二)-- Bash 变量
一、什么是Bash变量与变量分类
-
什么是变量?
变量就是计算机内存单元,其中存放的值可以改变。这个对于 有过计算机语言基础的同学应该理解起来应该不难。 那么关于变量的命名以及使用之类的这里不就不再过多的介绍,和其他计算机语言类似。 不过这里特别提出一点,在Bash中,变量的默认类型都是字符串类型,这一点和其他的语言要区分开来。
-
变量的分类
-
用户自定义变量
这种变量是用户自定义的,既可以改变它的变量名,也可以改变它的变量值。
-
环境变量
这种变量是主要保存系统操作环境相关的数据。变量可以自定义,但是对系统生效的环境变量名和变量作用是固定的。
-
位置参数变量
这种变量主要是用来向脚本文件中传递参数或者数据的,变量名不能够自定义,变量作用是固定的。它其实是预定义变量的一种。
-
预定义变量
这种变量是Bash中已经定义好的变量,变量名不能自定义,变量的作用也是固定的。
二、用户自定义变量
-
如何定义一个变量
变量名=变量值,这样就可以定义一个变量。注意,在其他编程语言规范中,运算符两边通常会加一个空格,例如Java中声明一个变量是这样的:
int i = 0
, 但是千万注意,在Bash中是不允许加空格的。正确示例:a=1
,反例:a = 1
或者a= 1
或者a =1
。 为什么会这样呢?这是因为如果加了空格,系统会认为“a”或者“a=”是一个命令,那么就会报command not found
错误。 -
如何使用一个变量
如果想要调用一个变量,只需要在前面加上“变量名”。示例:
echo $a
,就会输出变量a对应的值。 -
如何查看一个变量
使用
set
命令可以查看当前linux系统中全部的变量,以键值对的形式表现出来。默认情况下,如果我们输出一个不存在的变量,是不会报错的。 例如我们执行echo $abc
,我们从未定义名为“abc”的变量,所以这个变量不存在,但是不会报错,而是输出空。 但是如果我们输出一个变量结果是空,我们是无法确定这个变量到底是值为空字符串,还是说这个变量不存在。 此时,我们可以使用set -u
命令来达到如果调用了不存在的变量系统会报错的目的。 -
如何删除一个变量
使用
unset 变量名
可以删除一个变量。注意,删除变量的变量名前面不要加“$”。
三、环境变量
-
环境变量和用户自定义变量的区别
环境变量是全局变量,而用户自定义变量是局部变量。用户自定义变量只在当前的Shell生效,环境变量在当前Shell以及当前Shell的所有子Shell生效。
-
设置环境变量
语法:
export 变量名=变量值
,或者先声明变量变量名=变量值
,然后将它设置为环境变量export 变量名
。 -
查看环境变量
使用
set
查看全部的变量,包括环境变量。使用env
查看环境变量。 -
常见环境变量
-
PATH
我们知道,我们所使用的系统命令,其实都是已经预先写好的脚本文件,我们使用这些命令,就相当于执行了这些脚本文件,从而达到实现特定功能的目的。 那么我们想要执行这些脚本文件,就需要进入到这个文件的目录下,或者使用路径前缀来执行脚本。 例如,我们想要执行
ls
命令,理论上讲,我们需要cd /bin
,然后执行ls
,或者/bin/ls
。但是我们在实际的使用过程中,是从来不会带上/bin
前缀的,这其实就是PATH
环境变量的作用。 我们先查看一下PATH
变量的值。<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n53" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin</pre>我们会发现
PATH
的值是由冒号分隔的一个一个的路径。也就是当我们输入一个命令,Linux首先会去这些路径中找对应的脚本,找不到再找下一个,找到最后再找不到,会在当前路径下面去找。 所以如果我们想让我们自定义的脚本可以直接执行,而不需要进入到脚本的目录下,只需要使用PATH="$PATH":脚本所在的路径
(注意冒号不要漏掉),将我们的脚本所在的路径追加到PATH
中即可。 同样的,这样的操作方式也只是临时生效的,注销、重启等操作都会让这个操作失效。在Linux系统中一切皆文件,所以想要永久的生效,肯定还是需要修改相应的环境变量文件,没太大的难度,理解原理即可,这里不再赘述。 其实学过Java的朋友应该都明白环境变量意味着什么,这个理解起来应该没有什么难度的。
-
四、位置参数变量
变量 | 作用 |
---|---|
$n | n为数字,1-9代表第1-9个参数,10以上的参数需要用大括号包含,例如${10} |
$* | 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体 |
$@ | 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待 |
$# | 这个变量代表命令行中所有参数的个数 |
- 示例一
在我们的工作目录下创建一个脚本,然后输入如下代码:
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n76" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> vim demo1.sh
!/bin/bash
num1=2
sum=num1+sum</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n82" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> #!/bin/bash
echo "The parameter is : @"
echo "The number of parameters is : $#"</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n84" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> The parameter is : 1 2 3
The parameter is : 1 2 3
The number of parameters is : 3</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n90" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> #!/bin/bash
echo "使用$* 循环的结果如下"
for x in "x
done
echo "使用$@ 循环的结果如下"
for y in "y
done</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n92" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> 使用@ 循环的结果如下
1
2
3
4
5</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n115" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> #!/bin/bash
read -p "please enter your username : " -t 30 username
echo "your username is password"
read -p "please enter your sex [M/F] : " -n 1 sex
echo -e "\n"
echo "your sex is $sex"</pre>
<pre spellcheck="false" class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" lang="sh" cid="n117" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; padding: 10px 30px 10px 0px; border: 1px solid; width: inherit; background-position: inherit inherit; background-repeat: inherit inherit;"> please enter your username : test
your username is test
please enter your password :
your password is test
please enter your sex [M/F] : M
your sex is M</pre>
以上就是Shell脚本中变量相关的内容。不管您有任何的意见和建议都欢迎您联系我进行及时的沟通。 谢谢你百忙之中阅读本文,如果喜欢我的文章你也可以扫描下方二维码支持一下博主。博主只接受免费赞助,不接受包养!!!绝不!!!!!!除非你是美女,手动滑稽。
变量 | 作用 |
---|---|
$? | 最后一次执行的命令的返回状态。 如果这个变量的值为0,证明上一个命令正确执行; 如果这个变量的值非0(具体值由命令本身决定),则证明上一个命令执行错误。 |
$$ | 当前进程的进程号,即PID。 |
$! | 后台运行的最后一个进程的进程号。 |
五、预定义变量
可以看到执行之后,控制台提示please enter your username
,这是-p
参数的作用,而-t
参数的作用是限制“30s”时间输入,否则脚本自动执行下一步。 然后输入密码的时候,自动隐藏了密码,这是-s
的作用。之后please enter your sex [M/F] :
只要输入一个字符就会自动执行下一步,这是-n
的作用。
运行结果如下:
话不多说,写个脚本,demo4.sh
选项 | 作用 |
---|---|
-p | “提示信息”:在等待用户输入时,输出提示信息。 |
-t | read命令会一直等待用户输入,所以此选项用来限定用户输入的等待时间。 |
-n | read命令只接受指定字符数,就会执行。 |
-s | 隐藏输入的数据,用于机密信息的输入。 |
通过上面三个示例我们发现,上面的传递参数的方式对于使用者来说是很不友好的,如果使用者不知道脚本的内容,就不知道如何传递这些参数。 这时候我们就需要一个特殊的命令来引导用户输入参数以及接收用户输入的参数。 语法,read [选项] [变量名]
- 接收键盘输入---read
可以看到,脚本里运行了两个for循环,分别是对$*
和$@
的内容进行循环输出。 虽然两者都是代表了全部的参数,但是前者将所有的参数当成是一个整体,所以只有一次循环,并且将全部内容进行了一次打印。 但是后者是一次将每一个参数进行循环打印,打印了5次,这就是两者的区别。 这里暂时不需要去纠结for循环的语法,和其他语言没什么实质上的区别,就是换了个书写形式而已,后面的博文也会专门讲解一下一些语法问题。
运行结果为:
新建demo3.sh,输入如下代码:
- 示例三
可以看到$#
代表了传递的参数的个数,而$*
和$@
的结果似乎一样,那么他们俩的区别在哪儿呢?请看示例三
保存之后运行,sh demo2.sh 1 2 3
,得到结果如下:
新建一个脚本demo2.sh,输入如下代码:
- 示例二
保存之后运行,sh ./demo1.sh 2 3
,得到结果5。命令解释:我们在脚本文件中,$1
就代表了执行这个脚本的时候传递的第一个参数,也就是我们传递的2
。 同样的$2
就代表了第三个参数,也就是我们传递的3
,然后我们将这两个变量赋值给了num1和num2,然后进行求和并输出,所以得到的结果就是5
。 特殊说明,之前我们提到过,在Linux系统中,所有的变量默认都是字符串类型,所以直接输入$num1+$num2
,得到的结果是字符串相连接,而不是进行加法求和。 想要进行加法求和就需要用$()
将表达式包裹起来。这个后面的博文中会专门讲解Linux的运算。