您的位置:首页 > 运维架构 > Shell

Shell基础之Bash的变量——变量概述、自定义变量(本地变量)、环境变量、位置参数变量、预定义变量(预定义变量和接收键盘输入)

2019-07-08 11:57 931 查看

变量概述

Bash的变量分为:

  • 用户自定义变量
  • 环境变量
  • 位置参数变量
  • 预定义变量
1、什么是变量?

变量:变量是计算机内存的单元,其中存放的值可以改变。当Shell脚本需要保存一些信息时,如一个文件名或者一个数字,就把它存放在一个变量中。每个变量有一个名字,所以很容易引用它。使用变量可以保存有用的信息,使系统获知用户相关设置,变量也可以用于保存暂时信息。可以理解为:我是革命一块砖,那里需要那里搬。

2、变量设置规则
  • 变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”则是错误的;
  • 在Bash中,变量的默认类型都是字符串型,如果要进行数字运算,则必须指定变量类型为数值型。
  • 变量用等号连接值,等号两侧不能有空格;
  • 变量的值如果有空格,需要使用单引号或双引号括起来。在Linux当中,空格表示分割,便是命令、选项和参数的分割;
  • 在变量的值中,可以使用“ \ ”转义符;
  • 如果需要增加变量的值,那么可以进行变量值得叠加。不过变量需要用双引号包含“变量名”或变量名”或变量名”或{变量名}包含;
  • 如果是把命令的结果作为变量值赋予变量,则需要使用``反引号或$()包含命令;
  • 环境变量名建议大写,便于区分;

变量不能以数字开头,示例如下:

[root@root ~]# name='abc'
[root@root ~]# 2name='abc'
bash: 2name=abc: command not found

变量的值有空格,示例如下:

[root@root ~]# name=shen chao
bash: chao: command not found
[root@root ~]# name='shen chao'
[root@root ~]# echo name
name
3、变量分类

变量有上到下,限制越来越严格,但是位置参数变量和预定义变量的限制是一样的。

  • 用户自定义变量,变量名和变量值都随意,你喜欢那个就修改那个;
  • 环境变量:这种变量中主要保存的是和系统操作环境相关的数据。系统会有吸血默认的环境变量,系统默认的环境变量的名称不能更改,但是它的值可以按照你的需求去更改。但是系统允许用户定义自己的环境变量,也就是说我可以新添加我的环境变量名;
  • 位置参数变量:这种变量主要是用来相脚本当中传递参数或数据的,变量名不能自定义(变量名是固定的,不能更改),变量作用是固定的。并且不允许用户添加新的位置参数变量和预定义变量;
  • 预定义变量:是Bash中已经定义还的变量,变量名不能自定义,变量作用也是固定的;

其实,位置参数变量是预定义变量是当中的一种,只是位置参数变量相对来说较多,我们习惯性的将位置参数变量拿出来作为一个分类。但是从根本上来说,位置参数变量就是预定义变量。并且不允许用户添加新的位置参数变量和预定义变量。

一、用户自定义变量(本地变量)

变量定义:

命令格式:[root@localhost ~]# name=“zhao li ying”

变量叠加:

变量是允许叠加的,格式是:"变量1"变量2 或者 ${变量1}变量2,得到的结果就是:在原有变量1下在加上变量2。

[root@localhost ~]# aa=123

[root@localhost ~]# aa="$aa"456

[root@localhost ~]# aa=${aa}789

实例如下:

[root@root ~]# aa=123
[root@root ~]# echo $aa
123
[root@root ~]# aa="$aa"456
[root@root ~]# echo $aa
123456
[root@root ~]# aa=${aa}789
[root@root ~]# echo $aa
123456789
变量调用

命令格式是:echo + $变量名

命令格式:[root@localhost ~]# echo $name

变量查看

用set命令查看变量,set命令查看的是系统中的所有变量,包括系统中的环境变量、系统的定义变量,当然也包括我们自定义的一些变量。

命令格式:[root@localhost ~]# set

变量删除

命令格式是:unset + 变量名

命令格式:[root@localhost ~]# unset name

二、环境变量

环境变量中有一部分变量由系统定义的,我们把它称为系统环境变量,这些环境变量的名称是固定的,我们不能更改,一旦更改了就失去了它的作用了,但是我们只能允许修改它的值。但是我们可以在系统中定义自己的环境变量。即一部分是系统环境变量,一部分是自定义环境变量。

1、环境变量是什么?
  • 环境变量和本地变量的区分最主要的原因是:环境变量和本地变量作用的Shell的范围不同。
  • 用户自定义变量只在当前的Shell中生效;
  • 而环境变量会在当前Shell和这个Shell的所有子Shell当中生效。如果把环境变量写入相应的配置文件,那么这个环境变量就会在所有的Shell中生效。
2、设置环境变量

环境变量依然要遵循前面变量命名的规则,只需要在前面加一个export,export的意思是将这个变量声明为全局变量,让这个所有的Shell当中和这个子Shell中都可以查看这个变量。

命令格式:[root@localhost ~]# export 变量名=变量值

[root@localhost ~]# env
#查询变量。set命令是查看所有的变量,包括环境变量,但是env命令是专门用来查看环境变量的命令

[root@localhost ~]# unset 变量名
#删除变量

2.1> 如何定义一个子Shell

其实我们前面知道了,在我们当前的Shell当中可以写入标准的Shell,比如写cshell,就可以启动cshell,但是通过命令exit就可以退出回到之前的Shell。我能否在我当前的Shell当中能否启动一个bash(即,Linux的标准Shell),当然是可以的。这相当于在我们的父Shell底下又生成了一个子Shell(当然了这个子Shell,可以是cshell也可以是bash)。

  • 怎么查询和确定我们的shell呢?可以通过命令:pstress命令,这条命令的作用是确定进程数

父shell ——> 子(父)shell ——> 子(父)shell ——> … …

实例如下:
第一次:

[root@root ~]# csh
[root@root ~]# bash
[root@root ~]# pstree

执行结果如下:
第二次:

[root@root ~]# exit
exit
[root@root ~]# pstree

执行结果:

  • 再次总结:环境变量和本地变量的区别就是:如果是本地变量,在那个shell定义的变量,只能在这个Shell中能够看到。如果是环境变量,不光是这个Shell中能够看到,它的子Shell中也可以看到。

可以将自定义变量(本地变量)转化为环境变量(全局变量),通过在自定义变量名前面加export命令,命令格式:export 自定义变量

【1】示例如下:

[root@root ~]# name=sc
[root@root ~]# export age=18
[root@root ~]# sex=nan
[root@root ~]# export sex
[root@root ~]# set

运行结果如下:

【2】我们进入一个子Shell,如Bash,再执行set命令进行查看:

命令如下:

[root@root ~]# bash
[root@root ~]# pstree
.. ..
[root@root ~]# set

运行结果如下,本地变量姓名不见了;只剩下全局变量年龄和性别,年龄和性别被我声明成了环境变量,它们不仅在当前的Shell中生效,而且在在这个Shell当中的子Shell当中依然有效,这是我们用定义的方式定义的变量:

env命令运行如下:

3、系统常见环境变量

上面讲的死如何自定义环境变量,但环境变量用的最多的可能是系统自带的环境变量,即我们通过env命令看到的这些环境变量,定义了我们系统当前的环境名。我们重点讲两个环境变量:PATH和PS1。严格来说PS1不是环境变量,通过env命令查看不到,只能通过set命令来查看。其实PS1虽然不是环境变量,但是他是系统预留专门用于定义系统操作环境的这么一类变量,简单来说,PS1变量是环境变量中的一个子分支,只是用env命令看不到。PATH环境变量和PS1环境变量对系统而言有一些特殊含义,我们来看看。

3.1> PATH:系统查找命令路径

[root@root ~]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin

PATH="$PATH":/root/sh
#PATH变量叠加

  • (1)在Linux当中,我们的执行文件要运行,不管是系统的运行还是我自己写的脚本要运行都必须用路径(要么用绝对路径,要么用相对路径),但是我们系统命令的运行并没有写路径就可以执行,我们绝大多是的Linux系统命令都是二进制的可执行文件(即,是二进制计算机可以直接识别,但归根结底都是可执行文件),为什么不用路径就可以执行呢?原因就是因为PATH环境变量的存在。也就是说,当你敲一个命令,系统首先在PATH这个路径中按顺路一个一个找看有没有,没有就找下一个直到在/bin:下找到了这个命令(如,ls命令),它就会执行这条执行程序,如果在所有的路径当中都没有找到,那么这个时候系统就会报错,系统不能识别。

实例如下:

[root@root ~]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin[root@root ~]# ls
anaconda-ks.cfg  install.log.syslog  公共的  视频  文档  音乐
install.log      testfile            模板    图片  下载  桌面
[root@root ~]# lsddd
bash: lsddd: command not found
  • (2)我们首先写一个hello.shd的一个脚本

示例如下:

[root@root ~]# vi hello.sh
... ...

以下是hello.sh脚本的内容:

#!/bin/bash

echo "hello world!"

执行结果:

[root@root ~]# chmod 755 hello.sh
[root@root ~]# ./hello.sh
hello world!
[root@root ~]# /root/hello.sh
hello world!
  • (3)这个命令的执行只能通过相对路径或者绝对路径去执行。我们可以将hello.sh文件的路径拷贝到$PATH这个搜索的路径当中,当我们将hello.sh文件拷贝进去PATH路径当中时,这样hello.sh文件就不用通过路径(绝对路径或相对路径),而是通过PATH的这个搜索路径直接去执行了。其实Tab键的补全也是靠 $PATH 的搜索路径来实现的。这个就是“ PATH:系统查找命令的路径 ”我们可以通过执行如下命令去实现:

命令执行如下:

[root@root ~]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin[root@root ~]# cp hello.sh /bin/
[root@root ~]# hello.sh       *可以通过Tab键补全命令。其实Tab键的补全也是靠 $PATH 的搜索路径来实现的*
hello world!
  • (4)以上就是“ PATH:系统查找命令的路径 ”,但是我们并不习惯把我们自己写的脚本直接考拷贝到系统目录当中,不推荐改变系统原路的系统目录结构。比如他里面保存的是系统原有的目录,这样会搞乱的,让别人以为这是系统命令的。因此,我们还是习惯通过“PATH变量叠加”的方式来实现,这种写入是临时生效,一旦重启就会消失。

示例如下:

[root@root ~]# rm -rf /bin/hello.sh         *先删除/bin下的hello.sh文件*
[root@root ~]# hello.sh             *这个时候hello.sh文件,并没有写入到PATH目录下*
bash: /bin/hello.sh: 没有那个文件或目录
[root@root ~]# ./hello.sh               *我们只能通过路径来执行这个文件*
hello world!
[root@root ~]# PATH="$PATH":/root             *我们通过叠加的方式,叠加到PATH目录下面*
[root@root ~]# hello.sh                       *这个时候就可以通过PATH系统查找命令来执行了*
hello world!
[root@root ~]# echo $PATH               *通过echo查看PATH路径*
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin:/root
*可以看到我们的/root命令,通过变量叠加的方式写入到PATH目录下*

3.2> PS1:定义系统提示符变量

这种修改只是临时的,系统以启动就会消失了。

三、位置参数变量

位置参数变量的变量名称是固定的($n位置参数中n指的是:$0、$1、$3… …,在参数中的位置是固定的),并且作用也是固定的。

位置参数变量的优势是可以在命令执行的同时结束脚本,而不像我们后边讲的read命令执行完了之后,必须单独敲入命令才可以执行。

关于以上表格的说明:

  • $n:最主要的目的是接收用户向脚本中传递用户需要的值。当不输入任何位置参数是,运行结果是输出命令本身,因为0代表命令本身;0代表命令本身;0代表命令本身;n 就是用来把你的命令和命令后面跟的参数,传递给$0、$1、$2…$n代表的位置参数变量,最重要的作用是把命令行和命令的参数传递到脚本当中;
  • $* 和 $@的区别:$* 把所有的参数看成一个整体, $@把每个参数区别对待。主要还是为了区分我往脚本中传入的这两个参数是独立还是整体的。
  • $n的举例如下:
[root@root ~]# ls
anaconda-ks.cfg  install.log         testfile  模板  图片  下载  桌面
hello.sh         install.log.syslog  公共的    视频  文档  音乐
[root@root ~]# mkdir sh         #在/root目录下,创建sh目录
[root@root ~]# mv *.sh sh/             #并将/root目录下的所有.sh文件,都转移到/root/sh目录下
[root@root ~]# ls
anaconda-ks.cfg  install.log.syslog  testfile  模板  图片  下载  桌面
install.log      sh                  公共的    视频  文档  音乐
[root@root ~]# cd sh/              #进入sh目录
[root@root sh]# vi canshu1.sh             *创建canshu1.sh文件*

在canshu1.sh脚本中输入如下内容:
#!/bin/bash                         *在vi编译中的固定输入*

echo $0
echo $1
echo $2
echo $3

程序运行如下:
[root@root sh]# chmod 755 canshu1.sh
[root@root sh]# ./canshu1.sh     *当不输入任何位置参数是,运行结果是输出命令本身,因为$0代表命令本身*
./canshu1.sh

[root@root sh]# ./canshu1.sh 11 22 33        *第一个位置用$0接收,第二个位置用$1接收11,第三个位置用$2接收22,... ...*
./canshu1.sh
11
22
33
  • 写一个加法计算器(相关缺失命令参考前一个命令):
[root@root sh]# vi canshu2.sh

加法器脚本如下:
#!/bin/bash
num1=$1
num2=$2
sum=$(($num1 + $num2))
#变量sum的和是num1+num2
echo $sum
#打印变量sum的值

[root@root sh]# chmod 755 canshu2.sh
[root@root sh]# ./canshu2.sh 11 22
33
[root@root sh]# cat canshu2.sh
#!/bin/bash
num1=$1
num2=$2
sum=$(($num1 + $num2))

echo $sum
  • $* 、 $@和$#的区别的示例如下:
[root@root sh]# vi canshu3.sh

[root@root sh]# chmod 755 canshu3.sh
[root@root sh]# ./canshu3.sh 11 22 33 44 55 66 77 88 99
9
11 22 33 44 55 66 77 88 99
11 22 33 44 55 66 77 88 99
  • $*和$@的区别:
[root@root ~]# vi canshu4.sh        #创建canshu4.sh文件

在canshu4.sh脚本中输入一下内容:
#!/bin/bash
for i in "$"
#$*中的所有参数看成是一个整体,所以这个for循环只能循环一次
do
echo "The parameters is : $i"
done
x=1
for y in "$@"
#$@中的每个参数都看成独立的,所以“$@”中有几个参数,就会循环几次
do
echo "The paramenter$x is : $y"
x=$(( $x + 1 ))
done

运行结果如下:
[root@root ~]# chmod 755 canshu4.sh
[root@root ~]# ./canshu4.sh
The parameters is :

[root@root ~]# ./canshu4.sh 1 2 3 4 5
The parameters is : 1 2 3 4 5
1 2 3 4 5

位置参数变量的总结:位置参数最大的目的就是向程序中传递我们需要的值。但是位置参数有一个问题,除非这个脚本时你写的,否则你根本不清楚需要在我执行的脚本后面跟几个参数。因此在实际中我们建议使用其他的方式接收用户的键盘输入,而不是采用位置参数变量。位置参数变量在一些脚本中还是有作用的,包括我们系统自带的一些脚本,起码我们可以看懂这些参数是什么含义。

四、预定义变量

1、预定义变量

关于以上表格的说明:

  • 我们在前面多命令顺序执行中讲过&&(逻辑与)和||(逻辑或)。[命令1 && 命令2]只有当命令1正确执行,命令2才会执行,[命令1 || 命令2]只有当命令1不正确执行,命令2才会执行。那么命令2如何知道命令1正确执行与否呢?归根结底,就是判断$?的值,当$?的值为0时,表示命令1正确执行,当$?的值为非0时,表示命令1没有正确执行。
  • 第一个预定义变量[$?]意义:一般命令我们直接看结果就行,所以我们不需要写脚本来支持它。计算机程序只能通过[$?]命令来判断上一条命令是否正确执行。我们写得程序如何知道上一条命令正确之心关于否呢?就只能依赖[$?].
  • [$$]是显示当前进程的进程号(PID)。进程号(PID):每一个计算机进程或程序,它只要执行都会产生最少一个进程,程序复杂化话会产生多个进程,PID就是这个进程的ID号,计算机通过这个ID号来判断是那一个进程的。

注意:在Linux当中,要将某个进程放入后台,就必须要加&符号 ,表示这个进程没有终止,只是放在了后台执行。

find /root -name hello.sh &
#使用find命令在root目录下查找hello.sh文件
#符号&的意思是把命令放到后台执行。

示例说明:

#脚本内容如下:
#!/bin/bash

echo "The current process is $$"
#输出当前进程的PID。
#这个PID就是canshu5.sh这个脚本执行时,生成的进程PID

find /root -name hello.sh &
#使用find命令在root目录下查询hello.sh文件
#符号&的意思是把命令放入后台执行。
echo "The last one Daemon process is $!"

2、接收键盘输入

[root@localhost ~]# read [选项] [变量名]
.
选项:

  • -p “提示信息” : 在等待read输入时,输出提示信息
  • -t 秒数 : 没有-t选项的时候,read命令会一直等待用户输入,使用此选项可以指定等待时间
  • -n 字符数 : read命令只接收指定的字符数,就会执行
  • -s : 隐藏输入的数据,使用于机密信息的输入

关于以上命令的说明:

在位置参数变量中参数传递中,只有写的用户才知道,调用几个参数,且每个参数后面跟数值还是字符,别人都不清楚,在实际中很不现实。因此,用read做参数的传递可能更直观更符合实际情况。

  • -p 和 -t 的两个选项是必须写的,只要写read命令这两个选项是不能缺少的;
  • [变量名] : 当你手动输入任何内容,都会将值保存给变量,以便通过程序处理;
  • -p :可以在read输出的时候,在read等待接收的时候告诉用户“请你输入什么信息”,这样就会更直观
  • -t : 没有-t选项的时候,read命令会一直等待用户输入,使用此选项可以指定等待时间。
  • -n : -n + 字符数。如果不加-n,你必须enter回车这个read命令才能够结束。加字符数,例如你加了[-n 1]只要你输入一个字符,这个read就会执行。你写几个字符数,就接收几个字符,然后read就会执行。
  • -s : 隐藏输入的数据,比如需要输入用户密码时候,可以将信息隐藏起来的。“ [root@localhost ~]# read [选项] [变量名]”会将这个数据赋值给这个变量,你直接调用这个变量,就可以电泳我们输入的内容。

实例说明如下:

#!/bin/bash

read -t 30 -p "Please input your name:" name
#提示 “请输入姓名” 并等待30 秒,把用户的输入保存到变量name中
echo "Name is $name"
#打印出你输入的姓名信息

read -s -t 30 -p "Please enter your age:" age
#年龄是隐私,所以我们用 “-s” 选项隐藏输入
echo -e "\n"        #这条命令只是起到换行而已
echo "Age is $age"

read -n 1 -t 30 -p "Please select your gender[M/F]:" gender
#使用 “-n 1” 选项只接收一个输入字符就会执行,且要输入正确(都不用按回车enter键,就已经执行了)
encho -e "-n"
echo "Sex is $gender"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐