shell的变量功能

news2024/11/13 11:43:08

文章目录

  • shell的变量功能
    • 什么是变量?
      • 变量的可变性与方便性
      • 影响bash环境操作的变量
      • 脚本程序设计(shell script)的好帮手
    • 变量的使用与设置:echo、变量设置规则、unset
      • 变量的使用(echo)
      • 变量设置的规定
        • 使用案例
    • 环境变量的功能
      • 用env观察环境变量与常见环境变量说明
      • 用set观察所有变量(含环境变量与自定义变量)
        • PS1(提示字符的设置)
        • $(关于本shell的PID)
        • ?(关于上一个执行命令的返回值)
        • export(自定义变量转成环境变量)
    • 影响显示结果的语系变量(locale)
    • 变量的有效范围
    • 变量键盘读取、数组与声明:read、array、declare
      • read
        • 使用案例
      • declare,typeset
        • 使用案例
      • 数组(array)变量类型
    • 与文件系统及程序的限制关系
      • 使用案例
    • 变量内容的删除、取代与替换
      • 变量内容的删除与替换
      • 变量的测试与内容替换

shell的变量功能

变量是bash环境中非常重要的一个东西,我们知道Linux是多人多任务的环境,每个人登录系统都能取得一个bash shell,每个人都能够使用bash执行mail这个命令来接受自己的邮件等。bash如何得知你的邮箱是哪个文件的?这就需要变量的帮助。

什么是变量?

什么是变量呢?简单来说,就是让某一个特定字符串代表不固定的内容。

举例来说就像【y=ax+b】这东西,在等号左边的(y)是变量,在等号右边(ax + b)是变量内容,需要注意的是左边是未知数,右边是已知数。

变量的可变性与方便性

举例来说,我们每个账号的邮箱默认是以MAIL这个变量来进行存取的,当csq这个用户登录的时候,它便会取得MAIL这个变量,而这个变量的内容其实就是/var/spool/mail/csq,如果zhw登录呢?它取得的MAIL这个变量的内容其实就是/var/spool/mail/zhw。而我们使用邮件读取命令mail,来读取自己的邮箱时,这个程序可以直接读取MAIL这个变量的内容,这样就能够自动地分辨处属于自己的邮箱。
想要了解mail可以访问 : https://blog.csdn.net/qq_52089863/article/details/130175946?spm=1001.2014.3001.5501
image-20230421213344353

由于系统已经帮我们规划好MAIL这个变量,所以用户只要知道mail这个命令如何使用即可,mail会主动使用MAIL这个变量,如上图。

影响bash环境操作的变量

某些特定变量会影响到bash的环境。举例来说,你可以使用【echo ${PATH}】打印一下PATH变量,

会出现一堆目录里面放的可执行文件。你能不能在任何目录下执行命令,与PATH这个变量有很大的关系。例如你执行【ls】这个命令时,系统就是通过PATH这个变量里面的内容所记录的路径顺序来查找命令。如果说PATH变量内的路径没找到【ls】这个命令,那么就会在屏幕上显示【command not found】的错误信息,就是未找到命令的意思。

那么系统默认的变量除了PATH还有哪些呢?

  1. HOME:用户的主目录,通常是 /home/username。

  2. SHELL:默认的Shell程序。

  3. USER:当前登录的用户名。

  4. PWD:当前所在的工作目录。

  5. LANG:系统默认语言。

  6. TERM:终端类型。

  7. PS1:Shell提示符。

  8. PS2:Shell多行输入时的提示符。

  9. DISPLAY:X Window的显示器名称。

  10. EDITOR:默认的文本编辑器。

  11. HISTSIZE:历史记录的大小。

  12. HOSTNAME:当前主机的名称。

  13. MAIL:邮件的存储路径。

  14. SHLVL:表示Shell的嵌套深度,每次启动Shell时增加1。

脚本程序设计(shell script)的好帮手

这些还都只是系统默认的变量的目的,如果是个人的设置方面的应用:例如你要写一个大型脚本时,有些数据因为可能由于用户习惯的不同而有差异,比如说路径,由于该路径在脚本被使用在相当多的地方,如果下次换一台主机,都笑修改脚本里面所有路径,那么一定很麻烦。这个时候如果使用变量,而将该变量的定义写在最前面,后面相关的路径名称都以变量来替换,那么你只要修改一行就等于修改了整篇脚本,非常方便。

image-20230422204108301

简单来说变量就是一组文件或符号等,来替换一些设置或一串保留的数据,例如:我设置了【myname】就是【csq】,所以当你读取了【myname】这个变量时,系统自然就会知道,那就是【csq】,那么如何显示变量呢?这就需要用到【echo】这个命令

变量的使用与设置:echo、变量设置规则、unset

你可以利用echo这个命令来使用变量,但是,变量在被使用时,前面必须要加上【$】符号才行,假如你想要知道PATH内容

变量的使用(echo)

[root@localhost ~]# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin

利用echo就能够读出,只需要在变量名称前面加上 ,或是以 ,或是以 ,或是以{变量}的方式使用都可以(推荐使用${变量}

现在我们知道了变量与变量内容之前的相关性了,那么我要如何设置或是修改某个变量的内容呢?很简单,用等号(=)连接变量与它的内容就好,举例来说:我要将myname这个变量名称的内容设置为CSQ该如何设置呢?:

[root@localhost ~]# echo ${myname}
                       <== 这里没有显示任何数据,因为这个变量尚未被设置,是空的。
[root@localhost ~]# myname=CSQ  
[root@localhost ~]# echo ${myname}
CSQ                    <== 出现了,因为这个变量已经被设置了

在bash当中,当一个变量名称尚未被设置时,默认的内容是【空】,另外,变量在设置时,还是需要符合某些规定的,否则会设置失败。

变量设置的规定

  • 变量与变量内容以一个等号【=】来连接

例如:myname=CSQ

  • 等号两边不能直接接空格

例如:myname = CSQ

  • 变量名称只能是英文字母与数字,但是开头字符不能是数字

例如:2myname=CSQ

  • 变量内容若有空格可以使用双引号【"】或单引号【'】将变量内容结合起来,但双引号内的特殊字符如【$】等可以保有原本的特性

例如:yuyan=“lang is $LANG” 则echo ${yuyan}可得lang is zh_CN.UTF-8

  • 单引号内的特殊字符则仅为一般字符(纯文本)

例如:yuyan=‘lang is $LANG’ 则 echo ${yuyan}可得lang is $LANG

  • `可用转义符【\】将特殊符号如([Enter]、$、\、空格、’ 等)变成一般字符,
    如:myname=zhw\ Tsai 就可以打印出空格

  • 在一串命令的执行中,还需要借由其他额外的命令所提供的信息时,可以使用反单引号【`命令`】或【$(命令)】。特别注意,那个 ` 是键盘上方数字键 1 左边的那个按键,而不是单引号。

例如你想取得内核版本的信息:version=$(uname -r) 再输入 echo ${version} 可得内核版本

  • 若该变量为扩增变量内容时,则可用" 变量名称 " 或 变量名称"或 变量名称"{变量}累加内容

例如:PATH=" P A T H " : / h o m e / b i n 或 P A T H = PATH":/home/bin 或 PATH= PATH":/home/binPATH={PATH}:/home/bin

  • 若该变量需要在其他子程序执行,则需要以export来使变量变成环境变量

例如:export PATH

  • 通常大写字符为系统默认变量,自行设置变量可以使用小写字符,方便判断

  • 取消变量的的方法使用unset:【unset 变量名称】

例如:取消myname的设置 unset myname

上数内容中我们谈到子进程,那什么是子进程呢?就是说,在目前这个shell的情况下,去启用另一个新的shell,新的那个shell就是子进程。在一般的状态下,父进程的自定义变量是无法在子进程内使用的,但是通过export将变量变成环境变量后,就能够在子进程下面使用。

使用案例

设置变量name,且内容为csq

[root@localhost kernel]# 12name=csq
-bash: 12name=csq: 未找到命令                # 不能以数字开头
[root@localhost kernel]# name = csq
-bash: name: 未找到命令                      # 还是错的,等号两边不能有空格
[root@localhost kernel]# name=csq
[root@localhost kernel]# echo ${name}       
csq                                         # 这样才是成功的

若name的变量内容为CSQ’s name 就是变量内容含有特殊符号时:

[root@localhost kernel]# name=CSQ's name
# 单引号与双引号必须要成对  ,在上面的设置中只要一个单引号,因此你按下回车后
# 你还可以继续输入变量内容,这与我们需要的功不同
# 失败后按ctrl + c 结束进程
[root@localhost kernel]# name="CSQ's name"
# 在引号里面的单引号成为了一般字符,为什么不用单引号呢,因为单引号与内容中的单引号凑成了一对就不是原本的内容了
[root@localhost kernel]# echo $name
CSQ's name
[root@localhost kernel]# name=CSQ\'s\ name      # 利用转义字符把单引号和空格转义也是可以的
[root@localhost kernel]# echo $name
CSQ's name

我要在PATH这个变量中【累加】:/home/csq这个目录

[root@localhost kernel]# PATH=${PATH}:/home/csq  # 有很多种方法这里只举例一种

如果我要将name变量里面加一个yes呢?

[root@localhost kernel]# name=${name}yes
[root@localhost kernel]# echo $name
CSQ's nameyes

如何让我刚刚设置的name=csq可以用在下一个shell程序?

[root@localhost kernel]# name=csq       # 设置变量
[root@localhost kernel]# bash           # 进入子进程
[root@localhost kernel]# echo $name     # 进入后echo一下
                                        # 你会发现变量没有被设置
[root@localhost kernel]# exit           # 退出子进程
[root@localhost kernel]# export name    # 设置环境变量
[root@localhost kernel]# bash           # 进入子进程
[root@localhost kernel]# echo $name     # echo一下
csq                                     # 出现设置值了
[root@localhost kernel]# exit           # 退出子进程

如何进入到内核模块目录?

[root@localhost kernel]# cd /lib/modules/$(uname -r)/kernel
[root@localhost kernel]# cd /lib/modules/`uname -r`/kernel
# 两种方法都是可行的,一般采用第一种

取消我们刚刚设置的name的变量

[root@localhost kernel]# unset name

环境变量的功能

环境变量可以帮我们实现很多功能,包括根目录(主文件夹)的变换、提示字符的显示、执行文件查找的路径等,还有很多很多。那么,既然环境变量有那么多功能,目前我的shell环境种,有多少默认的环境变量呢?我们可以利用两个命令查看,【env】与【export】

用env观察环境变量与常见环境变量说明

列出目前shell环境下的所有环境变量

[root@localhost ~]# env
XDG_SESSION_ID=1
HOSTNAME=localhost.localdomain            # 这台主机的主机名称
SELINUX_ROLE_REQUESTED= 
TERM=xterm                                # 这个终端使用的环境是什么类型
SHELL=/bin/bash                           # 目前这个环境下,使用的shell是哪个程序
HISTSIZE=1000                             # history命令在Centos默认可记录1000条
SSH_CLIENT=192.168.100.1 50146 22
SELINUX_USE_CURRENT_RANGE=
OLDPWD=/lib/modules/3.10.0-1160.el7.x86_64/kernel
SSH_TTY=/dev/pts/0
USER=root                                 # 使用者的名称
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/home/csq
PWD=/root
LANG=zh_CN.UTF-8                   # 这个与语系有关
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root                         # 使用者的家目录
LOGNAME=root                       # 登录者用来登录的账号名称
SSH_CONNECTION=192.168.100.1 50146 192.168.100.10 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env                     # 上一次使用命令的最后一个参数

那么上面的变量有什么功能呢?我们来介绍一下(这个内容在影响bash环境操作的变量种谈到过)

  • HOME

代表用户的根目录

  • SHELL

告诉我们,目前这个环境是的SHELL是哪个程序

  • HISTSIZE

这个与历史命令有关,就是我们曾经执行过的命令会被系统记录下来,在之前的博客history中讲过

  • MAIL

当我们使用mail这个命令在收信时,系统会去读取的邮箱文件(mailbox)

  • PATH

就是执行文件查找的路径,目录与目录中间以冒号【:】分割,由于文件的查找是依序由PATH的变量内的目录查询的,所以目录的顺序也很重要

  • LANG

LANG变量是一个环境变量,用于指定当前系统所使用的默认语言和字符集。
在Linux和Unix系统中,LANG变量通常是在/etc/profile这个文件中定义的,它的值通常是一个类似于“en_US.UTF-8”的字符串,其中“en_US”表示语言,而“UTF-8”表示字符集

  • RANDOM

RANDOM是一个内置的环境变量,用于在Shell脚本中生成随机数。它生成的随机数是一个0到32767之间的整数。在每次调用时,它都会生成一个新的随机数。

使用RANDOM变量非常简单。只需要在脚本中使用$RANDOM即可。以下是一个生成随机数的例子:

[root@localhost 16:22:16 ~]# declare -i number=$RANDOM*10/32768+1 ;echo ${number}

在上面的例子中,declare -i number=$RANDOM*10/32768+1 会生成一个介于1到10之间的随机整数。可以使用这个随机数来进行各种操作,比如生成密码、随机选择列表中的选项等。

需要注意的是,RANDOM变量只能生成整数,如果需要生成小数,则需要进行一些额外的处理。

用set观察所有变量(含环境变量与自定义变量)

bash可不止有环境变量,还有一些与bash操作界面有关的变量,以及用户自己定义的变量存在。那么这些变量如何观察?这时候可以用set命令。set除了环境变量除外,还会将其他在bash内的变量通通显示出来,下面列举一部分内容。

[root@localhost ~]# set
BASH=/bin/bash    # bash的主程序路径
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")                            
BASH_VERSION='4.2.46(2)-release'   # 这两行是bash的版本
COLUMNS=109                        # 在目前的终端环境下,使用的栏位有几个字符长度   
HISTFILE=/root/.bash_history       # 历史命令记录的放置文件,隐藏文件
HISTFILESIZE=1000                  # 历史命令文件最大记录数1000(存在上面这个变量文件里)
HISTSIZE=1000                      # 内存中记录历史命令条数最大1000条
IFS=$' \t\n'                       # 默认的分隔符号
LINES=24                           # 目前终端下的最大行数
MACHTYPE=x86_64-redhat-linux-gnu   # 安装的机器类型
OSTYPE=linux-gnu                   # 操作系统类型
PS1='[\u@\h \W]\$ '                # 命令提示符
PS2='> '                           # 如果你使用转义字符(\),这是第二行以后的提示字符
$                                  # 目前中shell所使用的PID
?                                  # 刚刚执行完命令的返回值
.......
....
...

PS1(提示字符的设置)

PS1就是我们的命令提示符。当我们每次按下[Enter]按键去执行某个命令后,最后要再次出现提示字符时,就会主动去读取整个变量值。上面PS1内显示的是一些特殊符号,这些特殊符号可以显示不同的信息。下面我们来介绍一下

  • \d:显示出【星期 月 日】 的日期格式,如【Mon Feb 2】

  • \H:完整的主机名。举例来说【localhost.localdomain】

  • \h:仅取主机名在第一个小数点前的名字,如【localhost】

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

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

  • \A:显示时间,为24小时格式的【HH:MM】

  • @:显示数据,为12小时格式的【am/pm】

  • \u:目前用户的账户名称,如【csq】

  • \v:BASH的版本信息

  • \w:完整的工作目录名称,由根目录写起的目录名称,单根目录会以~替换

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

  • \# :执行的第几个命令

  • \KaTeX parse error: Expected 'EOF', got '#' at position 21: …,如果是root时,提示字符为#̲,否则就是

让我们来看看Centos默认的PS1内容吧【[\u@\h \W]\$】现在你知道那些反斜杠后的参数的意义了吧?要注意,那个反斜杠后的参数为PS1的特殊功能,与bash的变量设置没关系,不要搞混了,那你现在知道了为何你的命令提示字符是【[root@localhost ~]# 】了吧?

那么假设我想要给命令提示字符添加一个显示时间为24小时格式的【HH:MM:SS】该怎么添加呢?

[root@localhost ~]# PS1='[\u@\h \W \t]\$'    
[root@localhost ~ 13:49:49]# 
# 看到了吗,提示字符变了

$(关于本shell的PID)

美元符本身也是一个变量。整个东西代表的是目前这个shell的进程号,就是所谓的PID。想要知道我们的shell的PID,就可以用【echo $$】,就会出现我们shell的PID

[root@localhost ~ 13:53:42]# echo $$
9937

?(关于上一个执行命令的返回值)

问好也是一个特殊的变量,在bash里面这个变量很重要。这个变量是上一个执行的命令所返回的值。当我们执行某个命令的时候,这些命令都会返回一个执行后的代码。一般来说执行成功会返回一个0值,如果执行过程中失败,就会返回错误的代码,一般就是非0的数值来替换

[root@localhost ~ 14:03:47]# echo $SHELL
/bin/bash                                  # 可以顺利执行没有错误
[root@localhost ~ 14:04:02]# echo $? 
0                                          # 没有错误所以返回0
[root@localhost ~ 14:04:06]# 1name=csq
bash: 1name=csq: 未找到命令                 # 发生错误了
[root@localhost ~ 14:04:21]# echo $? 
127                                        # 因为发生了错误,返回错误(非0)
  • OSTYPE,HOSTTYPE,MACHTYPE(主机硬件与内核的等级)
  1. OSTYPE(操作系统类型)
    OSTYPE是一个环境变量,它指示当前操作系统的类型。这个变量在不同的操作系统中有不同的名称,例如,在Linux中,它被称为 O S T Y P E ,在 M a c O S 中,它被称为 OSTYPE,在MacOS中,它被称为 OSTYPE,在MacOS中,它被称为SYSTEM_TYPE。OSTYPE的值通常是一个字符串,表示操作系统的名称和版本号,例如,linux-gnu、darwin、win32等。
  2. HOSTTYPE(主机类型)
    HOSTTYPE也是一个环境变量,它指示当前主机的类型。这个变量在不同的操作系统中有不同的名称,例如,在Linux中,它被称为 H O S T T Y P E ,在 M a c O S 中,它被称为 HOSTTYPE,在MacOS中,它被称为 HOSTTYPE,在MacOS中,它被称为MACHTYPE。HOSTTYPE的值通常是一个字符串,表示主机的类型和处理器架构,例如,x86_64、i686、armv7等。
  3. MACHTYPE(机器类型)
    MACHTYPE是一个环境变量,它指示当前机器的类型。这个变量通常是由HOSTTYPE和其他信息组成的,以提供更详细的硬件和内核等级信息。MACHTYPE的值通常是一个字符串,表示主机的类型、处理器架构、操作系统类型和内核类型等信息,例如,x86_64-pc-linux-gnu、armv7l-unknown-linux-gnueabihf等。

export(自定义变量转成环境变量)

谈了env和set现在知道所谓的环境变量与自定义变量,那么两者之间有啥差异?其实这俩者差异在于【该变量是否会被子进程所继续引用】。什么是子进程?什么是父进程呢?

当你登录Linux并取得一个bash后,你的bash就是一个独立的进程,这个进程的识别使用的是进程标识符,也就是PID。接下来你在这个bash下面所执行的任何命令都是由这个bash衍生出来的,那些被执行的命令就被称为子进程。如下图

image-20230423142954077

如上图所示,我们在原本的bash下面执行另一个bash,结果操作的环境界面就会跑到第二个bash去(就是子进程),那原本的bash就会暂停情况(睡着了sleep),整个目录运行的环境是实践的部分。若要回到原本的bash中去,就只有将第二个bash结束掉(执行 exit 或 logout)才行。

这个进程概念与变量由啥关系?关系很大,因为子进程会继承父进程的环境变量,子进程不会继承父进程的自定义变量。所以你在原本bash的自定义变量进入子进程后就会消失不见,一直到你离开子进程并回到原本的父进程后,这个变量才会出现。

那我们就可以使用export命令,可以让变量内容继续在子进程中使用

export 变量名称

用于共享自己的变量设置给后来调用的文件或其他进程

如果仅执行export而没有接变量时,那么此时就会把所以的环境变量显示出来

[root@localhost ~ 14:10:33]# export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="localhost.localdomain"
...........
......
..

影响显示结果的语系变量(locale)

Linux到底支持多少语系呢?可以由locale来查询

[root@localhost ~ 14:45:43]# locale -a
......
...
zh_CN
zh_CN.gb18030    # gbk 中文编码
zh_CN.gb2312
zh_CN.gbk     
zh_CN.utf8       # 简体中文编码
....
....

那么我们如何自定义这些编码呢?其实可以通过下面这些变量

[root@localhost ~ 14:46:03]# locale
LANG=zh_CN.UTF-8                    # 主语言的环境
LC_CTYPE="zh_CN.UTF-8"              # 字符(文字)辨识编码
LC_NUMERIC="zh_CN.UTF-8"            # 数字系统的显示信息
LC_TIME="zh_CN.UTF-8"               # 时间系统的显示数据
LC_COLLATE="zh_CN.UTF-8"            # 字符的比较与排序
LC_MONETARY="zh_CN.UTF-8"           # 币值格式的显示等
LC_MESSAGES="zh_CN.UTF-8"           # 信息显示的内容,如功能表,错误信息等。
....
...
....
LC_ALL=                             # 整体语系的环境

基本上,你可以逐一设置每个与语系有关的变量数据,但事实上,如果其他的语系变量都未设置,且你有设置LANG或是LC_ALL,则其他的语系变量就会被这两个变量所替换,这就是我们在Linux中,通常说明仅设置LANG或LC_ALL这两个变量而已,因为它是最主要的设置变量。

当然每个用户可以去调整自己喜欢的语系,系统默认的语系定义在哪里呢?其实就在/etc/locale.conf里面

[root@localhost 15:08:52 ~]# vim /etc/locale.conf
  LANG="zh_CN.UTF-8"

系统原本是中文语系,所有显示的数据通通是中文。但为了网页显示的关系,需要将输出转成英文语系才行,但是又不想写入配置文件,毕竟暂时显示使用,应该怎么做

[root@localhost 15:13:00 ~]# LANG=en_US.UTF-8
[root@localhost 15:13:45 ~]# export LC_ALL=en_US.UTF-8
[root@localhost 15:14:00 ~]# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8

变量的有效范围

变量的有效范围?我们上面的export命令说明中,就提到了这个概念。如果在运行程序的时候,有父进程与子进程的不同进程关系时,则变量可否被引用与export有关,被export后的变量,我可以称它为环境变量,环境变量可以被子进程所引用,但是其他的自定义变量内容就不会存在与子进程中。

为什么环境变量的数据可以被子进程所引用呢?这是因为内存配置的关系

  • 当启动一个shell,操作系统会分配一内存区域给shell使用,此内存中的变量可以让子进程使用。
  • 若在父进程利用export功能,可以让自定义变量的内容写到上述的内存区域当中(环境变量)
  • 当你加载另一个shell时(即启动子进程,而离开原本的父进程)子shell可以将父shell的环境变量所在的内存区域导入自己的环境变量区块当中。

通过这样的关系,我们就可以让某些变量在相关的进程之存在,帮助自己更方便地操作环境。

变量键盘读取、数组与声明:read、array、declare

read

要读取来自键盘输入的变量,就是要使用read这个命令。这个命令最常被用在shell脚本的编写当中,想要跟用户交互?用这个命令就对了

read  [-pt]    变量
选项:
-p:后面可以接提示字符
-t:后面可以接等待的【秒数】

使用案例

让使用者由键盘输入一内容,将该内容变成名为atest的变量

[root@localhost 15:46:33 ~]# read atest
This is atest                   # 光标会等待你输入,输入This is atest
[root@localhost 15:53:59 ~]# echo ${atest}
This is atest                   # 你刚刚输入的数据已经变成一个变量的内容

提示使用者30秒输入自己的名字,将输入字符作为名为named的变量内容

[root@localhost 15:54:09 ~]# read -p "please keyin your name: " -t 30 named
please keyin your name: csq                # 这里是提示字符,输入csq
[root@localhost 15:57:05 ~]# echo ${named}
csq                                        # 发现输入的数据又变成了一个变量的内容

declare,typeset

declare或typeset是一样的功能,就是声明变量的类型。如果使用declare后面没有接任何参数,那么bash就会主动的将所有的变量名称与内容通通显示出来,就好像set一样。

declare [-aixr] 变量
选项:
-a: 将后面名为xxxx的变量定义成为数据(array)类型
-i:将后面名为xxxx的变量定义成为整数(integer)类型
-x:用法与export一样,就是将后面的变量变成环境变量
-r:将变量设置成为readonly类型,该变量不可被更改内容,也不能unset

使用案例

让变量sum进行100+300+50的求和结果

[root@localhost 16:15:28 ~]# sum=100+300+50
[root@localhost 16:15:38 ~]# echo ${sum}
100+300+50              # 为什么没有 帮我们求和,因为这个是文字形式的变量属性
[root@localhost 16:15:41 ~]# declare -i sum=100+50+300
[root@localhost 16:16:11 ~]# echo ${sum}
450                     

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

  • 变量类型默认为字符串,所以若不指定变量类型,则1+2为一个字符串而不是计算式。所以上述第一个执行的结果才会是那种情况
  • bash环境中的数值运算,默认最多仅能到达整数形态,所以1/3结果为0

现在你晓得为什么你要进行变量声明了吧?如果需要非字符串类型的变量,那就得要进行变量的声明才行。

让sum变成环境变量

[root@localhost 16:28:45 ~]# export |grep sum
declare -ix sum="450"       # 出现了,包括由i与x的定义

让sum变成只读属性,不可修改

[root@localhost 16:28:54 ~]# declare -r sum
[root@localhost 16:30:03 ~]# sum=111
-bash: sum: readonly variable    # 不能改这个变量了!

让sum变成非环境变量的自定义变量吧

[root@localhost 16:30:16 ~]# declare +x sum        # 将-变成+可以进行【取消】操作
[root@localhost 16:31:38 ~]# declare -p sum        # -p可以单独列出变量的类型
declare -ir sum="450"       # 只剩下,i,r的类型,不具有x

declare也是个很有用的功能,尤其是当我们需要使用到下面的数组功能时,它也可以帮我们声明数组的属性。数组在shell脚本中也是很常用的。如果你不小心将变量设置为【只读】,通常要注销在登录能恢复该变量的类型。

数组(array)变量类型

那么如何设置数组的变量与内容呢?

var[index]=content

意思说我有一个数组名为var,这个数组的内容为var[1]=小明,var[2]=小弔,var[3]=老明,那个index就是一些数字,重点是用中括号[]来设置。

[root@localhost 16:45:56 ~]# var[1]="small ming"
[root@localhost 17:09:46 ~]# var[2]="bro ming"
[root@localhost 17:10:12 ~]# var[3]="old ming"
[root@localhost 17:10:24 ~]# echo "${var[1]},${var[2]},${var[3]}"
small ming,bro ming,old ming

与文件系统及程序的限制关系

想象一个状况,文档Linux主机里面同时登录了10个人,这10个人不知道怎么高的,同时开启了100个文件,每个文件大小约为10MB,请问一下,Linux内存要多大才够他们使用?

[root@localhost ~]#  declare -i sum=10*100*10  ; echo $sum
10000

10000MB=10GB,这样,内存完全不够他们用。为了预防这个情况的发生,所以我们的bash是可以限制用户的某些系统资源的,包括可以开启的文件数量,可以使用CPU时间,可以使用内存的总量

ulimit [-SHacdfltu] [配额]
选项:
-H:hard limit  严格的设置,必定不能超过这个设置的数值
-S:soft limit  警告的设置,可以超过这个设置值,超过则有警告信息
                在设置上面,通常soft 会比hard小
-a:后面不接任何选项与参数,可列出所有的限制与额度。
-c:当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用)
    这种文件就被称为内核文件。为此限制每个内核文件的最大容量
-f:此shell可以建立的最大文件容量(一般可能设置为2GB)单位为Kbytes
-d:程序可使用的最大段内存容量
-l:可用于锁定的内存量
-t:可使用的最大CPU时间(单位为秒)
-u:单一使用者可以使用的最大进程数量

使用案例

列出你目前身份(假设为一般账号)的所有限制数据数值

[csq@localhost ~]$ 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) 31116
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

限制使用者仅能建立10MBytes以下的容量文件

[csq@localhost ~]$ ulimit -f 10240
[csq@localhost ~]$ ulimit -a |grep 'file size'
core file size          (blocks, -c) 0
file size               (blocks, -f) 10240
[csq@localhost ~]$ dd if=/dev/zero of=10mb bs=1M count=15
文件大小超出限制

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

变量除了可以直接设置来修改原本的内容之外,有没有办法通过简单的操作来将变量的内容进行微调呢?

变量内容的删除与替换

先让小写的path自定义变量设置的与PATH内容相同

[csq@localhost ~]# path="$PATH"
[root@localhost ~]# echo ${path}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin

假设我不喜欢local/bin 这个目录,所以要将一个目录删掉,如何显示?

[root@localhost ~]# echo ${path#/*local/bin:}
/usr/sbin:/usr/bin:/root/.local/bin:/root/bin

删除前面所有的目录,仅保留最后一个目录

[root@localhost ~]# echo ${path##/*:}
/root/bin

因为在PATH这个变量内容中,每个目录都是以冒号【:】隔开的,所以要从头删掉目录就是介于斜线(/)到冒号(:)之间的数据。但是PATH中不止一个冒号(😃,所以#与##就分别代表:

  • #:符合替换文字的【最短的】那一个
  • ##:符合替换文字的【最长的】那一个

上面谈到的是从前面开始删除变量内容,那么如果想要从后面向前删除变量内容?这个时候就得使用百分比(%)符号了

我想要删除最后面那个目录,就是从:到bin为止的字符

[root@localhost ~]# echo ${path%:*bin}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin
# 注意最后面一个目录不见了
# 这个%符号代表由最后面开始向前删除

那如果我只想要保留第一个目录?

[root@localhost ~]# echo ${path%%:*bin}
/usr/local/sbin

假设你是csq,那你的MAIL变量应该是/var/spool/mail/csq,假设你只想保留最后面那个文件名,前面的目录名称都不要了,如何利用$MAIL变量来完成?(最长符合)

[root@localhost ~]# echo ${MAIL##/*/}
root

相反如果你只想拿掉文件名,保留目录名称,即【/var/spool/mail/】最短符合。

[root@localhost ~]# echo ${MAIL%/*}
/var/spool/mail

将path的变量内容内的sbin替换成大写的SBIN

[root@localhost ~]# echo ${path/sbin/SBIN}
/usr/local/SBIN:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin
# 这个部分就容易理解了。关键字在于那两个斜线,量斜线的中间的是旧字符
# 后面的是新字符,所以结果就会出现如上述的特殊字体不放
[root@localhost ~]# echo ${path//sbin/SBIN}
/usr/local/SBIN:/usr/local/bin:/usr/SBIN:/usr/bin:/root/.local/bin:/root/bin
# 如果是两条斜线,那么就变成所有符合的内容都会被替换。
变量设置方式说明
KaTeX parse error: Expected '}', got '#' at position 4: {变量#̲关键词} <br />②{变量##关键词}①若变量内容从头开始的数据符合【关键词】,则将符合的最短数据删除
②若变量内容从头开始的数据符合【关键词】,则将符合最长数据删除
KaTeX parse error: Expected '}', got 'EOF' at end of input: {变量%关键词}<br />②{变量%%关键词}①若变量内容从尾向前的数据符合【关键词】,则将符合的最短数据删除
②若变量内容从尾向前的数据符合【关键词】,则将符合的最长数据删除
变量 / 旧字符串 / 新字符串 < b r / > ② {变量/旧字符串/新字符串}<br />② 变量/旧字符串/新字符串<br/>{变量//旧字符串/新字符串}①若变量内容符合【旧字符串】则【第一个旧字符串会被新字符串替换】
②若变量内容符合【旧字符串】则【全部的旧字符串会被新字符串替换】

变量的测试与内容替换

测试以下是否存在username这个变量,若不存在则给予username内容为root

[root@localhost ~]# echo ${username}
                                          # 出现空白,所以username不存在,也可能是空字符
[root@localhost ~]# username=${username-root}
[root@localhost ~]# echo ${username}
root                                      # 因为username没有设置,所以主动给予名为root的内容
[root@localhost ~]# username="This is csqcsqcsq"    # 主动设置username的内容
[root@localhost ~]# echo ${username}
This is csqcsqcsq                         # 因为username已经设置了

不过这还是有点问题。因为username可能已经被设置为【空字符串】了。果真如此的话,那你还可以使用下面的案例来给予username的内容为root

若username未设置或未空字符,则将username内容设置为root

[root@localhost ~]# username=""
[root@localhost ~]# username=${username-root}
[root@localhost ~]# echo ${username}
             # 因为username被设置为空字符了,所以当然还是保留为空字符。
[root@localhost ~]# username=${username:-root}
[root@localhost ~]# echo ${username}
root         # 加上【:】后若变量内容为空或是未设置,都能够以被后面的内容替换

大括号内有没有冒号【:】的差别还是很大的。加上冒号,被测试的变量未被设置或是已被设置未空字符串时,都能够用后面的内容来替换与设置。

下面例子中,那个var与str为变量,我们想要针对str是否有设置来决定var的值,一般来说,str:代表【str没设置或为空的字符串时】,至于str则仅为【没有该变量】

变量设置方式str没有设置str为空字符串str已设置非为空字符串
var=${str-expr}var=exprvar=var=$str
var=${str:-expr}var=exprvar=exprvar=$str
var=${str+expr}var=var=exprvar=expr
var=${str:+expr}var=var=var=expr
var=${str=expr}str=expr
var=expr
str不变
var=
str不变
var=$str
var=${str:=expr}str=expr
var=expr
str=expr
var=expr
str不变
var=$str
var=${str?expr}expr输出至stderrvar=var=$str
var=${str:?expr}expr输出至stderrexpr输出至stderrvar=$str

根据上面这张表,我们来进行几个案例练习,首先来测试以下,如果旧变量(str)不存在时,我们要给予新变量一个内容,若旧变量存在则新变量内容以旧变量来替换,结果如下:

测试:假设str不存在(用unset)然后测试以下减号(-)的用法

[root@localhost ~]# unset str;var=${str-newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=newvar,str=       # 因为str不存在,所以var为newvar

测试若str已存在,测试一下var会变怎样?

[root@localhost ~]# str="oldvar";var=${str-newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=oldvar,str=oldvar  # 因为str存在,所以var等于str的内容

如果你想要将旧变量内容也一起替换掉的话,那么就使用等号(=)

[root@localhost ~]# unset str;var=${str=newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=newvar,str=newvar         # 因为str不存在,所以var str 均为newvar

测试如果str已经存在了,测试一下var会变怎样?

[root@localhost ~]# str="oldvar";var=${str=newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=oldvar,str=oldvar      # 因为str存在,所以var等于str的内容

那如果我只是向指定,如果旧变量不存在时,整个测试就告知我【有错误】,此时就能够使用问号【?】的帮忙

测试:若str不存在时,则var的测试结果直接显示“无此变量”

[root@localhost ~]# unset str;var=${str?}
-bash: str: 参数为空或未设置

测试:若str存在时,则var的内容会与str相同

[root@localhost ~]# str="oldvar";var=${str?novar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=oldvar,str=oldvar   # 因为str存在,所以var等于str的内容

基本上这种变量的测试也能通过shell脚本内的【if…then…】来处理,不过bash有提供这么简单的方式来测试变量,那我们也可以学一学。

旧变量内容也一起替换掉的话,那么就使用等号(=)
先假设str不存在用(unset),然后测试一下等号(=)的用法

[root@localhost ~]# unset str;var=${str=newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=newvar,str=newvar         # 因为str不存在,所以var str 均为newvar

测试如果str已经存在了,测试一下var会变怎样?

[root@localhost ~]# str="oldvar";var=${str=newvar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=oldvar,str=oldvar      # 因为str存在,所以var等于str的内容

那如果我只是向指定,如果旧变量不存在时,整个测试就告知我【有错误】,此时就能够使用问号【?】的帮忙

测试:若str不存在时,则var的测试结果直接显示“无此变量”

[root@localhost ~]# unset str;var=${str?}
-bash: str: 参数为空或未设置

测试:若str存在时,则var的内容会与str相同

[root@localhost ~]# str="oldvar";var=${str?novar}
[root@localhost ~]# echo "var=${var},str=${str}"
var=oldvar,str=oldvar   # 因为str存在,所以var等于str的内容

基本上这种变量的测试也能通过shell脚本内的【if…then…】来处理,不过bash有提供这么简单的方式来测试变量,那我们也可以学一学。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/453801.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构(五)—— 栈与队列(2)

一、接上章 栈与队列的中等、困难题。 堆是一块动态内存 栈是先进后出的堆的一种方法 队列是一种先进先出的线性表 二、题 2.5 150 逆波兰表达式求值 很有意思的一道题&#xff0c;将中缀表达式 4 13 / 5&#xff0c;转化为后缀表达式之后&#xff1a;["4", &qu…

深入理解机器学习——过拟合(Overfitting)与欠拟合(Underfitting)

分类目录&#xff1a;《深入理解深度学习》总目录 机器学习的主要挑战是我们的算法必须能够在先前未观测的新输入上表现良好&#xff0c;而不只是在训练集上表现良好。在先前未观测到的输入上表现良好的能力被称为泛化&#xff08;Generalization&#xff09;。通常情况下&…

测试需求平台6-数据持久化与PyMySQL使用

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版&#xff0c;拥抱Vue3.0将前端框架替换成字节最新开源的arco.design&#xff0c;其中约60%重构和20%新增内容&#xff0c;定位为从 0-1手把手实现简单的测试平台开发教程&#xff0c;内容将囊括基础、扩展和实战&a…

信息安全技术 健康医疗数据安全指南 付下载地址

声明 本文是学习GB-T 39725-2020 信息安全技术 健康医疗数据安全指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 数据使用管理办法示例 第一章 总则 第一条 为规范数据使用流程&#xff0c;根据国家相关法律法规及相关规定&#xff0c;特制定本…

imgaug Augment Polygons 对标注图片和polygons的数据增强

对于本地化进行图像的增强&#xff0c;大家都是非常好操作的。但是&#xff0c;对于标注信息一起增强&#xff0c;还是稍微有一些难度的&#xff0c;麻烦很多。 我是遇到一个数据集非常少的任务&#xff0c;只有40张图。就直接标记了去训练&#xff0c;发现几乎不拟合&#xf…

这一篇搞定Spring

文章目录 一、引言1.1 原生web开发中存在哪些问题&#xff1f; 二、Spring框架2.1 概念2.2 访问与下载 三、Spring架构组成四、山寨版的Spring容器4.1准备工作4.2 山寨IOC容器4.3 配置文件告诉容器 管理哪些bean4.4 相关类4.5 测试 容器 五、构建Maven项目5.1 新建项目5.2 选择…

深度强化学习——AlphaGo实例讲解(5)

现在我们来分析AlphaGo这个实例&#xff0c;看看深度强化学习是怎么样用来玩围棋游戏的 AlphaGo的主要设计思路&#xff1a; 首先是训练&#xff0c;要分3步来做&#xff1a; 1、behavior cloning&#xff1a;这是一种模仿学习&#xff0c;alphaGo模仿人类玩家&#xff0c;从…

STM32平衡小车 pid简单学习

自动控制系统 自动控制系统可分为开环控制系统和闭环控制系统。 1、开环控制系统开环控制系统(open-loop control system)指被控对象的输出(被控制量)对控制器(controller)的输出没有影响。在这种控制系统中&#xff0c;不依赖将被控量反送回来以形成任何闭环回路。 2、闭环控…

c++入门(下)

C入门&#xff08;下&#xff09; 对于C的基础语法的讲解&#xff0c;由想要实现多次重复的函数&#xff0c;引出宏函数和inline的内联函数的对比&#xff0c;对于inline的讲解和运用&#xff0c;在后&#xff0c;C语言中的NULL和C中独特的nullptr的相比两者的比较&#xff0c…

kong(4):限流配置

Kong 提供了 Rate Limiting 插件&#xff0c;实现对请求的限流功能&#xff0c;避免过大的请求量过大&#xff0c;将后端服务打挂。 Rate Limiting 支持秒/分/小时/日/月/年多种时间维度的限流&#xff0c;并且可以组合使用。例如说&#xff1a;限制每秒最 多 100 次请求&…

Windows Server 2012R2 安装mysql 丢失VCRUNTIME140_1.dll------亲测

无去启动此程序,因为计算机中丢失VCRUNTIME140_1.dll。尝试重新安装该程序以解决此问题。 1.解决思路 说到底还是缺少底层的依赖&#xff0c;先下载依赖然后安装&#xff0c;最后安装vc。要不然vc是安装不成功。 下载安装--一下的插件 安装过程中需要重启一次电脑。 注意:必…

Android LoaderManager AsyncTaskLoader加载全部图片RecyclerView BigImageView呈现,Java(1)

Android LoaderManager AsyncTaskLoader加载全部图片RecyclerView BigImageView呈现&#xff0c;Java&#xff08;1&#xff09; 权限&#xff1a; <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:n…

VUE3子组件-业务代码优化

Vue3子组件 1.简介 Vue 3组件的主要优势之一就是它们可以帮助你将你的应用程序分解成可维护和可重用的部分。当你在应用程序中多次使用相同的代码时&#xff0c;你可以将它们抽象成一个组件&#xff0c;然后在应用程序中的多个地方使用该组件&#xff0c;而不必每次都编写相同…

5年了,终于入职阿里测试岗位,直接涨薪30K...

前言 本科毕业后就一直从事软件测试的工作&#xff0c;和多数人一样&#xff0c;最开始从事功能测试的工作&#xff0c;看着自己的同学一步一步往上走&#xff0c;自己还是在原地踏步&#xff0c;说实话这不是自己想要的状态。 一年半后开始沪漂生活&#xff0c;又摸爬滚打了…

阿里巴巴软件测试面试过了,起薪20k

普通二本计算机专业毕业&#xff0c;从毕业后&#xff0c;第一份接触测试的工作是在一家通讯小公司&#xff0c;大部分接触的工作是以功能测试为主&#xff0c;一直都是几千块钱工资&#xff0c;还一度被派出差&#xff0c;以及兼职各种产品、运维、运营的活&#xff0c;感觉自…

Cleer ARC II 音弧

戴上Cleer ARC II 音弧解放双耳&#xff0c;享受更自由的音符 用惯了各种入耳式耳机&#xff0c;换上开放式耳机&#xff0c;戴着确实更加舒服&#xff0c;特别是我现在用的这款Cleer ARC II 音弧&#xff0c;戴上还不容易掉&#xff0c;很适合运动使用。这款耳机采用一种耳挂佩…

JavaEE1(4/23)

目录 1.计算机CPU 2.CPU和GPU的区别 3.线程 4.内存是如何分配的 5.进程的调度 6.线程和进程的区别和联系&#xff1f; 1.计算机CPU 主频 &#xff1a;运算速度 3.73Ghz 表示每秒计算37.3亿次 基准速度&#xff1a;最小计算速度 睿频&#xff1a;最大运行速度 超频&…

【头歌C语言程序设计】结构体解答

写在前面 这道题总体来说还是偏难的&#xff0c;如果只看代码比较难以理解&#xff0c;当结构体的文章发出后&#xff0c;就有许多小伙伴问我这个问题&#xff0c;我开始意识到&#xff0c;可能我对这道题所作的解答还不够&#xff08;不装了&#x1f601;&#xff0c;根本没有…

Python进阶篇(三)-- TCP套接字与UDP套接字编程

1 Python3 网络编程 1.1 介绍 本文将首先利用 Python 实现面向TCP连接的套接字编程基础知识&#xff1a;如何创建套接字&#xff0c;将其绑定到特定的地址和端口&#xff0c;以及发送和接收数据包。其次还将学习 HTTP 协议格式的相关知识。在此基础上&#xff0c;本篇将用 Pyt…

Spring boot项目编译后未能加载静态资源文件

起因: 因甲方爸爸加了一个紧急的需求: 需要搞一个文件上传和下载功能. 我心中想:这不简单,搞个资源服务器,将上传文件放上去,然后访问资源链接就行了. 但接下来甲方爸爸说 不需要这莫麻烦,直接将文件放服务器里,用的时候下载到资源文件夹下就行. 我心里想: 我擦嘞 还能这样!! 然…