Linux的Bash——(二)Shell的变量

2. Shell的变量

2.1 什么是变量?

变量就是以特定的字符串代表不固定的内容

变量的优点又有那些?

(1) 可变性与方便性

关于可变性和方便性,我相信如果有接触过至少一门编程语言就能很快Get到这个点,所谓的: 一改全改 ,特别是在脚本程序设计(shell script)中起了非常大的作用
对于要反复引入的而又复杂的内容,使用变量真的太合适了,例如我们的:路径、版本名等

  • 补充:硬件环境下,一般也会用到变量来代替值,使得某些值更具有表象意义,例如: LED_ON=0; LED_OFF=1;

(2) 影响bash环境操作的变量

在我们的bash当中,某些特定的变量也会影响我们的命令是否能正常运行。在前面我们也提到过,bash的命令分为内嵌和外部。
例如我们在 第一章所提到过的 ls 这条指令的路径就是在 “/etc/bin” 当中,其中变量 PATH 就决定我们能不能在任何的目录下运行命令。

深入来说,由于在Linux System所有的线程都需要一个运行码,如同上面所提到的,真正shell 来跟Linux 沟通,是在正确登录Linux系统之后,而在这之前,由于系统需要一些变量在提供数据的存取,所以一些所谓的 环境变量 就需要读入到系统中,例如: PATH、HOEM、MAIL、SHELL

  • 为了与普通变量区分,一般环境变量都是大写的(国际通用规则啦)

2.2 echo,变量配置守则

变量与变量代表的内容之间的关系是怎么样的呢?这就必须要引入一下命令帮助我们更好的理解

(1) 变量的取用:echo

  • 取用&获取
    取用变量或者说获取变量内容的方法很简单,就是在变量名称前面加上$,或者是以${变量}的方式来取都是可以的

  • 配置&修改
    更为简单,只需要用等号(=)连接变量与内容即可配置或者修改变量成功

  • 例子

    [tanzitao@manager ~]$ echo $PATH          <-- 获取环境变量
    /opt/torque/bin:/opt/torque/sbin:/home/tanzitao/.vscode-server/  <-- 环境变量内容 
    [tanzitao@manager ~]$ TZT=test      <-- 配置变量(TZT)
    [tanzitao@manager ~]$ echo $TZT     <-- 查询变量
    test                                <-- 获取结果
    
  • 补充:当一个变量名没有给配置的时候都是空的

(2) 变量的配置守则

  • 变量与变量的内容以一个等号连接,且等号两边都不能有空格

    [tanzitao@manager ~]$ tag = tanzitao   <-- 有空格,错误
    bash: tag: 未找到命令
    [tanzitao@manager ~]$ tag=tanzitao     <-- 无空格,正确
    
  • 变量名只能由英文和中文,但是不能以数字开头

    [tanzitao@manager ~]$ 1tag=tanzitao    <-- 数字开头
    bash: 1tag=tanzitao: 未找到命令         <-- 报错
    [tanzitao@manager ~]$ tag=tanzitao     <-- 字母开头 没报错
    
  • 变量的如果有空格符可以使用双引号["] 或 [']将变量的内容结合起来,但是两者之间却又存在差异

    [tanzitao@manager ~]$ var="lang is $LANG"  <-- 使用了["]
    [tanzitao@manager ~]$ echo $var
    lang is zh_CN.UTF-8                        <-- 成功输出结果
    [tanzitao@manager ~]$ var='lang is $LANG'  <-- 使用了[']
    [tanzitao@manager ~]$ echo $var
    lang is $LANG                              <-- 输出字符串本身
    
    ps: 两者的区别就在于:双引号["]会高级点,能够将变量中的的变量值读取出来,而单引号[']内的字符为一班字符
    
  • 可以跳脱的字节 [ \ ]将特殊符号(如[Enter],$,,空格符,'等) 变成一般字符

    [tanzitao@manager ~]$ var='lang \
    > ^C
    [tanzitao@manager ~]$ var="lang is \
    > $LANG"
    
  • 在一串命令当中如果还需要用到其他的命令提供信息,可以使用反引号[`命令`] 或者 [$(命令)]的形式在命令当中嵌入命令

    [tanzitao@manager ~]$ version="version`uname -r`" | echo $version    <-- 使用[\`命令\`]方式嵌入命令
    version=3.10.0-1160.15.2.el7.x86_64
    [tanzitao@manager ~]$ version="version=$(uname -r)" | echo $version  <-- 使用[$(命令)]方式嵌入命令
    version=3.10.0-1160.15.2.el7.x86_64
    
  • 若变量为扩增变量的内容时,可以用 “$变量名称” 或者 ${变量}累加内容

    [tanzitao@manager ~]$ echo $sum
    1
    [tanzitao@manager ~]$ sum="$sum"+2  <-- 直接跟在后面 特别注意! '+' 不代表连接符
    [tanzitao@manager ~]$ echo $sum
    1+2
    
  • 若变量需要在其他的子程序当中运行,可以使用 export

    [tanzitao@manager ~]$ name=tanzitao <-- 初始化变量
    [tanzitao@manager ~]$ echo $$       <-- 查看当前程序的PID
    6227                                <-- 当前Bash程序的PID
    [tanzitao@manager ~]$ bash          <-- 开启子程序
    [tanzitao@manager ~]$ echo $$       <-- 查看当前程序的PID
    3177                                <-- 当前Bash程序的PID
    [tanzitao@manager ~]$ echo $name    <-- 获取变量内容(无结果)
    
    [tanzitao@manager ~]$ exit          <-- 退出子程序
    exit
    [tanzitao@manager ~]$ echo $$       <-- 查看程序PID
    6227                                <-- 确认回到当前程序
    [tanzitao@manager ~]$ export name   <-- 变量转换为环境变量
    [tanzitao@manager ~]$ bash          <-- 再次进入子程序
    [tanzitao@manager ~]$ echo $name    <-- 获取变量内容
    tanzitao                            <-- 显示结果
    
  • 大写:系统默认变量;小写:自行配置变量

  • 取消变量使用 unset

2.3 环境变量的功能

环境变量的主要功能:home目录的变换、提示字符的显示、运行文件搜索的路径

(1) 用 env 观察环境变量与常见环境变量的说明

  [tanzitao@manager ~]# env
  HOSTNAME=manager               <-- 这部主机的主机名
  TERM=xterm-256color            <-- 这个终端机使用的环境是什么类型
  SHELL=/bin/bash                 <-- 目前这个环境下,使用的 Shell 是哪一个程序?
  HISTSIZE=1000                  <-- 记录命令的笔数在 CentOS 默认可记录 1000 笔
  USER=tanzitao                  <-- 使用者的名称
  LS_COLORS=...                  <-- 一些颜色显示
  MAIL=/var/spool/mail/tanzitao  <-- 这个用户所取用的 mailbox 位置
  PATH=/home/tanzitao/bin       <-- 运行文件命令搜寻路径
  INPUTRC=/etc/inputrc           <-- 与键盘按键功能有关。可以配置特殊按键!
  PWD=/home/tanzitao             <-- 目前用户所在的工作目录 (利用 pwd 取出!)
  LANG=en_US                     <-- 这个与语系有关,底下会再介绍!
  HOME=/home/tanzitao            <-- 这个用户的家目录啊!
  _=/home/tanzitao               <-- 上一次使用的命令的最后一个参数(或命令本身)
  • RANDOM

这是一个 随机的随机数变量 可以通过 $RANDOM的方式生成随机数。在一般情况的$RANDOM的变量范围在0-32767范围内

  [tanzitao@manager ~]$ declare -i number=$RANDOM*10/32768; echo $number
  7                                    <-- 取出0-9范围内的随机变量

(2) 用 set 观察所有变量(环境变量+自定义变量)

  [tanzitao@manager ~]# set
  BASH=/bin/bash                                   <-- bash 的主程序放置路径
  BASH_VERSINFO=("x86_64-redhat-linux-gnu")        <-- bash 的版本
  BASH_VERSION='4.2.46(2)-release'                 <-- 也是 bash 的版本啊!
  COLUMNS=156                                      <-- 在目前的终端机环境下,使用的字段有几个字符长度
  HISTFILE=/home/tanzitao/bash_history             <-- 历史命令记录的放置文件(隐藏文档)
  HISTFILESIZE=1000                                <-- 存起来(与上个变量有关)的文件之命令的最大纪录笔数。
  HISTSIZE=1000                                    <-- 目前环境下,可记录的历史命令最大笔数。
  HOSTTYPE=x86_64                                  <-- 主机安装的软件主要类型。
  IFS=$' \t\n'                                     <-- 默认的分隔符
  LINES=35                                         <-- 目前的终端机下的最大行数
  MAILCHECK=60                                     <-- 与邮件有关。每 60 秒去扫瞄一次信箱有无新信!
  OLDPWD=/home                                     <-- 上个工作目录。我们可以用 cd - 来取用这个变量。
  OSTYPE=linux-gnu                                 <-- 操作系统的类型!
  PPID=20025                                       <-- 父程序的PID (会在后续章节才介绍)
  PS1='[\u@\h \W]\$ '                              <-- PS1命令提示字符,也就是我们常见的[root@www ~]# 或 [dmtsai ~]$ 的配置值
  PS2='> '                                         <-- 如果你使用跳脱符号 (\) 第二行以后的提示字符也
  name=VBird                                       <-- 刚刚配置的自定义变量也可以被列出来喔!
  $                                                <-- 目前这个 shell 所使用的 PID
  ?                                                <-- 刚刚运行完命令的回传值。      
PS1:(提示字符的配置)

首先需要的注意的是PS1后面不是应英文字母,是数字1,其实PS1就相当于我们的 命令提示字符 当我们每次按下 Enter 去运行某些命令都会出现

  [tanzitao@manager ~]$ echo $PS1  <-- 查看我们的提示字符
  [\u@\h \W]\$                     <-- 具体内容(符号意义在下面讲)
  [tanzitao@manager ~]$            <-- 每一行都会存在的命令提示字符

源格式:[\u@\h \W]\$

  • \d : 可显示出 星期 月 日 的日期格式

    [tanzitao@manager SCOW]$ PS1="[\d@\u \h]\$"
    [二 7月 26@tanzitao manager]$
    下面的可以自主尝试
    
  • \H : 完整的主机名

  • \h : 仅取主机名在第一个小数点之前的名字

  • \t : 显示时间,为24小时的 HH:MM:SS

  • \T : 显示时间,为12小时的 HH:MM:SS

  • \A : 显示时间,为24小时的 HH:MM

  • @ : 显示时间,为12小时的 am/pm 样式

  • \u : 目前使用者的账号名称如:root

  • \v : BASH的版本信息

  • \w : 完整的工作目录名称

  • \W : 利用basename函数取得工作目录名称,列出最后一个目录的名字

  • \# : 下达的第几个命令

  • \$ : 提示字符,如果是root时,提示字符为 # 否则是 $

$:(关于本地shell的PID)

所谓的PID就是(Process ID),通过 echo $$ 可以读取当前Shell的PID

?:(关于上个运行命令的回传值)
  • 只要上一句话成功执行就会回传一个0
  • 只要上一句话运行发生错误就会回传一个非0的错误代码

(3) export: 自定义变量转化为环境变量

经过对命令 envset 的认识,了解到了什么环境变量和自定变量,那么这两者具体的差异是什么呢?总的来说概括为一句话:该变量是否会被子程序所继续应用

当我们登录Linux并取得一个bash程序之后,接下来的任何命令都是由这个bash所衍生出来的,那些被下达的命令就成为子程序。下图展示了父程序与子程序之间的概念:


图1:父程序与子程序

原本在bash下运行另外一个bash,结果操作的环境就会跑道第二个bash当中,原本的bash就被暂停。只要暂定子程序的bash就能会到父程序当中

至于 export 的用法以及父程序和子程序的演示在本章前面部分已经演示过了,就不再重复

2.4 变量的有效范围

变量的有效范围在学习 export 的时候就已经提及了,在程序运行的时候,有父程序和子程序之间的关系,则变量是否能被应用和export有很大的关系

  • 在某些不同的数据会谈论到[全局变量]与[局部变量],可以这样看待:
    环境变量=全局变量
    自定义变量=局部变量

为什么环境变量的数据可以被子程序所应用呢?
因为这是内存分配的关系,操作过程如下

  • 当启动一个shell,操作系统会自动分配给一些给予区块给shell,这个内存变量和一让字程序免费用
  • 若在附程序利用了export,可以昂自定义的变量内容写在上述的记忆区域中(环境变量)
  • 当加载另外一个shell,子shell可以将父shell的环境变量所在记忆块导入记得环境变量当中

2.5 变量键盘读取、数组与宣告: read,array,declare

变量配置都是由命令直接配置的,那么可不可以由用户经过键盘进行输入呢?就是说,在某些程序运行的过程中需要用户输入“yes/no”之类的信息,在bash里也有相对应的功能

(1) read

要读取来自键盘输入的变量,那就需要用到read这个命令了。这个命令最常被用在shell script当中。

  [tanzitao@manager SCOW]# read [-pt] variable
  选项与参数:
  -p  :后面可以接提示字符
  -t  :后面可以接等待的秒数
  
  # 例子1:read的使用
  [tanzitao@manager SCOW]$ read test        <-- 使用read命令 会等待用户输入
  This is a test                            <-- 输入"test"变量的内容
  [tanzitao@manager SCOW]$ echo $test       <-- 取出变量内容
  This is a test

  # 例子2:read参数的使用
  [tanzitao@manager SCOW]$ read -p "input your name:" -t 20 name  <-- "-p"后跟提示字符 "-t"后跟等待时间(s)
  input your name:tzt
  [tanzitao@manager SCOW]$ echo $name
  tzt

read的命令就像是c语言当中 scanf() 一样,在程序中实现程序和使用者交流

(2) declare / typeset

declaretypeset 的功能是一样的,都是用来宣告变量的类型

  [tanzitao@manager SCOW]$ declare [-aixr] variable
  选项与参数:
  -a  :将后面名为 variable 的变量定义成为数组 (array) 类型
  -i  :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
  -x  :用法与 export 一样,就是将后面的 variable 变成环境变量;
  -r  :将变量配置成为 readonly 类型,该变量不可被更改内容,也不能 unset

  # 例子1:declare -i的使用
  [tanzitao@manager SCOW]$ sum=1+3+5              <-- 初始化变量为"计算式"形式的"字符串"
  [tanzitao@manager SCOW]$ echo $sum
  1+3+5                                           <-- 结果为"字符串"
  [tanzitao@manager SCOW]$ declare -i sum=1+3+5   <-- 定义sum变量为整数数字类型
  [tanzitao@manager SCOW]$ echo $sum
  9                                               <-- 结果为计算式的结果

在默认的情况下,bash对于变量有几个基本的定义:

  • 变量得类型默认为 字符串 ,如果不指定类型,呢么1+2就是一个 字符串 而不是 计算式

  • bash环境中的数值运算,默认最多仅能达到整数的形态,所以1/3结果是0

    # 例子2:declare -x的使用
    [tanzitao@manager SCOW]$ declare -x sum         <-- 将变量转化为环境变量 
    [tanzitao@manager SCOW]$ export | grep sum
    declare -ix sum="9" 
    
    # 例子3:declare -r的使用
    [tanzitao@manager SCOW]$ declare -r sum         <-- 变量转化为只读,内容不可更改
    [tanzitao@manager SCOW]$ sum=123
    -bash: sum: 只读变量
    [tanzitao@manager SCOW]$ declare +x sum         <-- 使用"+"可以取消变量的设置
    [tanzitao@manager SCOW]$ declare -p sum
    declare -ir sum="9"
    

(3) 数组(array)变量类型

在某些时候,我们必须使用该数组来宣告一些变量,这既需要用到数组的变量类型,首先明确一点,在bash里头,数组的配置方式是:var[index]=content

  • var:数组名

  • [index]:下标

  • content:变量内容

    [tanzitao@manager SCOW]$ var[1]="small min"
    [tanzitao@manager SCOW]$ var[2]="big max"
    [tanzitao@manager SCOW]$ var[3]="nice max"
    [tanzitao@manager SCOW]$ echo "${var[1]}, ${var[2]}, ${var[3]}"               <-- 需要注意数组的取出变量的方式
    small min, big max, nice max
    

数组的读取方式需要注意:建议直接以 ${数组} 的方式来读取

2.6 与文件系统以及程序的限制关系:ulimit

bash可以通过限制用户的某些系统资源,从而预防系统的资源溢出

  [tanzitao@manager SCOW]$ ulimit [-SHacdfltu] [配额]
  选项与参数:
  -H  :hard limit ,严格的配置,必定不能超过这个配置的数值;
  -S  :soft limit ,警告的配置,可以超过这个配置值,但是若超过则有警告信息。
        在配置上,通常 soft 会比 hard 小,举例来说,soft 可配置为 80 而 hard 
        配置为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时,
        系统会有警告信息通知你!
  -a  :后面不接任何选项与参数,可列出所有的限制额度;
  -c  :当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),
        这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。
  -f  :此 shell 可以创建的最大文件容量(一般可能配置为 2GB)单位为 Kbytes
  -d  :程序可使用的最大断裂内存(segment)容量;
  -l  :可用于锁定 (lock) 的内存量
  -t  :可使用的最大 CPU 时间 (单位为秒)
  -u  :单一用户可以使用的最大程序(process)数量。

  [tanzitao@manager SCOW]$ ulimit -a
  core file size          (blocks, -c) 0          <-- 只要是 0 就代表没限制
  data seg size           (kbytes, -d) unlimited
  scheduling priority             (-e) 0
  file size               (blocks, -f) unlimited  <-- 可创建的单一文件的大小
  pending signals                 (-i) 31191
  max locked memory       (kbytes, -l) 64
  max memory size         (kbytes, -m) unlimited
  open files                      (-n) 1024      <-- 同时开启文件的数量
  pipe size            (512 bytes, -p) 8
  POSIX message queues     (bytes, -q) 819200
  real-time priority              (-r) 0
  stack size              (kbytes, -s) 8192
  cpu time               (seconds, -t) unlimited
  max user processes              (-u) 4096
  virtual memory          (kbytes, -v) unlimited
  file locks                      (-x) unlimited

2.7 变量内容的删除、取代与替换

变量除了可以直接配置来修改原本的内容以外,还可以对变量的内容进行删除、取代与替换

(1) 变量内容的删除与代替

  例1: 对于\#和\##的使用
  [tanzitao@manager SCOW]$ var="123 1234 12345"   <-- 初始化变量
  [tanzitao@manager SCOW]$ echo ${var#*3}         <-- 使用 "#" 检索变量 "*"代表任何内容且不限制
  1234 12345

对于变量:${var#*3}
${}: 关键词:再删除模式必须存在
var: 原本变量的内容
#: 删除or替代的关键字:“#” 代表从变量内容最前面开始删除,且只删除最短的部分
*3: 需要删除的部分 "*"是通配符*

  例子2: #和##的区别
  对于%和%%的使用
  [tanzitao@manager SCOW]$ echo ${var#*3}
  1234 12345
  [tanzitao@manager SCOW]$ echo ${var##*3}
  45

  #:删除从头开始搜索符合变量最短的哪一个
  ##:删除从头开始搜索符合变量最长的哪一个

  例子3:对于%和%的使用
  [tanzitao@manager SCOW]$ echo ${var%3*}
  123 1234 12
  [tanzitao@manager SCOW]$ echo ${var%%3*}
  12

  %:删除从尾开始搜索符合变量最短的哪一个
  %%:删除从尾开始搜索符合变量最长的哪一个

  例子4: 对于对于/和//的使用
  [tanzitao@manager SCOW]$ echo ${var/3/9}
  129 1234 12345
  [tanzitao@manager SCOW]$ echo ${var//3/9}
  129 1294 12945
变量配置方式内容
${变量#关键词}
${变量##关键词}
变量内容从头开始寻找数据,若符合关键词,则将符合的最短数据删除
变量内容从头开始寻找数据,若符合关键词,则将符合的最长数据删除
${变量%关键词}
${变量%%关键词}
变量内容从尾开始寻找数据,若符合关键词,则将符合的最短数据删除
变量内容从尾开始寻找数据,若符合关键词,则将符合的最长数据删除
${旧字符串/新字符串}
${变量//旧字符串/新字符串}
若变量内容符合旧字符串,则将第一个旧字符串替换为新字符串
若变量内容符合旧字符串,则将所有旧字符串替换为新字符串

(2) 变量的测试与内容替换

在某些时候,我们常常会需要判断某个变量是否存在,如果变量存在就使用既有的配置,如果变量不存在就给予一个常用的配置。

  例子1: 测试一下是否存在 username 这个变量,若不存在则给予 username 内容为 root
  [tanzitao@manager SCOW]$ echo $username               <-- 读取空变量

  [tanzitao@manager SCOW]$ username=${username-root}    <-- 如果username有内容就保留,如果不存在就赋值为"root"
  [tanzitao@manager SCOW]$ echo $username
  root`                                                 <-- 赋值为root
  [tanzitao@manager SCOW]$ username="tzt"               <-- 变量赋值
  [tanzitao@manager SCOW]$ username=${usern ame-root}   <-- 如果username有内容就保留,如果不存在就赋值为"root" 
  [tanzitao@manager SCOW]$ echo $username
  tzt

对于命令:new_var=${old_var-content}
new_var: 新的变量,主要是来取代旧变量,一般来说名称是一样的
${}: 关键词部分,必须要存在
old_var: 旧的变量,被测试的项目
content: 变量的内容,这部分是在给予为配置变量的内容

不过这样的配置也有可能会出现问题,就是说username可能已经被配置为了 空字符串 不过只需要加入一点小改动就能避免这种情况的发生

  例子2:若 username 未配置或为空字符串,则将 username 内容配置为 root
  [tanzitao@manager SCOW]$ username=""                  <-- 变量配置空字符串
  [tanzitao@manager SCOW]$ username=${username-root} 
  [tanzitao@manager SCOW]$ echo $username
                                      <-- 因为username 被配置为了空字符串,所以保留为空字符串
  [tanzitao@manager SCOW]$ username=${username:-root}
  [tanzitao@manager SCOW]$ echo $username
  root                          <-- 加上 ":" 后边亮的内容若是空或者未配置都能够被后面的内容替换
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑狗_Hugo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值