Shell(六):变量和引用

1、变量

  变量用于保存有用虚拟性,Linux用户使用变量定制其工作环境,使系统获知用户相关的配置。变量本质上是存储数据的一个或多个计算机内存地址。

1.1、变量的分类

  变量可分为:本地变量、环境变量和位置参数。

  本地变量仅可在用户当前Shell生命期的脚本中使用的变量,本地变量随着Shell进程的消亡而无效,类似C、Java等语言的局部变量。

  环境变量适用于所有由登录进程锁产生的子进程,是在用户登录后到注销之前的所有编辑器、脚本、程序和应用中都有效。

  位置参数,用于向Shell脚本传递参数,是只读的。

1.2、变量替换和赋值

  Shell的三类变量中,位置参数是只读变量,没有变量的替换和赋值操作。其他两类变量有上述操作。

  变量是某个值的名称,引用变量值就称为变量替换,$符号是变量替换符号,如 variable 是变量名,那么,$varibale就表示变量的值。

  将值赋给某个变量名就称为变量赋值,变量赋值有两种格式,如下所示:

variable=value
${variable=value}

变量的赋值说明:

  等号两边可以有空格,不影响赋值操作;

  若值(value)中包含空格,则必须用双引号括起来;

  变量名只能包含大小写字母(a~z和A~Z)、数字(0~9)、下画杠(_)等符号,并且变量名不能以数字开头,否则视为无效变量名。

0

  $varibale 和 ${variable} 都表示变量的值,即进行变量替换,其次,如果值中有空格,需要用双引号引起来。

0

  变量赋值可以使用另一个变量,variable4赋值时使用了variable3变量,echo命令输出 variable4 时 自动查找 variable2 的值,然后拓展变量,显示整个变量值。

  unset命令可以清除变量的值,命令格式为:

unset 变量名

  unset将 variable4 变量清除后,echo 命令输出空白行,表示 variable4 变量未被初始化。

0

  变量赋值的模式,详情如下:

模式

含义

variable=value

将value值赋给变量variable

variable+value

对已赋值的variable,重设其值

variable?value

variable:?value

对未赋值的variable,显示系统错误信息

variable:=value

对未赋值的variable,将value值赋给它

variable:-value

对未赋值的variable,将value值赋给它,但value值不存储到variable对应的地址空间

  ":=" 和 ":-" 是两种常用的符号,":=" 和 ":-" 都不对变量进行重新赋值。

0

  使用 ":=" 和 ":-" 需要用花括号将赋值式子括起来,否则,shell将 shape:=circular 整个字符串当做变量名进行处理。

0

  清除shape变量,在分别输出${shape:-circular},${shape:=circular},$shape的值,结果表明:":-"符号未将blue真正存储到shape中,":="符号将blue真正存储到shape中。

  ":?"和"?"可用于测试变量是否被赋值,若变量未赋值,Shell提示错误信息:

0

  变量可以设置为只读,变量一旦设置了只读,任何用户不能对此变量进行重新赋值,若有用户对此变量重新赋值,Shell提示错误信息。设置只读可以使用readonly关键字。

variable=value
readonly variable

  当变量设置为只读时,对其进行重新赋值时,会提示错误信息:

0

1.3、无类型的Shell脚本变量

  Shell脚本变量是无类型的,与awk变量一样,bash Shell不支持浮点型,只支持整型和字符型,默认情况下,Shell脚本变量是字符型的,同时,字符型的变量还具有一个整型值,为0。

  Shell会根据上下文判断出数值型的变量,并进行变量的算术运算和比较等数值操作。判断标准是变量中是否只包含数字,如果变量只包含数字,则Shell认定该变量是数值型的,反之,Shell认定该变量是字符串。

  新建 var01.sh 脚本,详情如下:

#!/bin/bash

a=2023
# 让a加 1
let "a+=1"
echo "a=$a"

b=xx09
echo "b=$b"
# 将b强制定义为整型
declare -i b
echo "b=$b"

# 让b加1
let "b+=1"
echo "b=$b"

exit 0

  赋予权限并执行脚本,结果如下:

0

  var01.sh脚本首先定义a变量,值为2023,然后将a的值增加1,在输出a的值,shell自动将 a 解析为数值变量,a=2024。let 命令用于在变量上执行算术运算,let "a+=1" 等价 a+=1。

  b变量,值为xx09,b是字符型的,利用declare命令将b强制转化为整型,发现b的值并未改变,即declare强制转化并未起作用。将b执行算术操作,增加1,结果为b=1,即字符型变量的数值为0。

  declare命令与typeset命令一样,用于定义和限制变量的属性,declare -r可将变量设置为只读,等价于readonly命令。

  下面来看看Shell对空字符串和未定义变量的处理方式,新建declar.sh,详情如下:

#!/bin/bash

# 定义c 为空字符串
b=""
echo "b=$b"
let "b+=1"
echo "b=$b"

# 不预先定义e ,直接输出
echo "c=$c"
let "c+=1"
echo "c=$c"

exit 0
  定义变量 b 为空字符串,将 b 执行算术操作,增加 1,结果为 c=1,即空字符串变量的数值仍为0。declare.sh脚本直接输出未曾预先定义的变量c,结果c为空值,将c加1,结果 c = 1。

0

  Shell脚本变量是无类型的,并且Shell变量同时有数值型和字符型两种赋值,数值型的初值为 0,字符型的初值为空,而且可以不预先定义变量而直接使用。

1.4、环境变量

1.4.1、定义和清除环境变量

  环境变量是无类型的,环境变量的特殊之处仅在于它的值适用于所有由登录进程所产生的子进程。定义环境变量的格式如下:

# 定义环境变量的基本格式
ENVIRON-VARIABLE=value    # 环境变量赋值
export ENVIRON-VARIABLE   # 声明环境变量

  在给环境变量赋值后,用export命令声明一下,就说明此变量为环境变量,环境变量的名称一般由大写字母组成。  

0

  SEHLLSCRIPT变量赋值为/home/shell/script,再利用export命令将 SEHLLSCRIPT 声明为环境变量。

可使用env命令,可列出系统中所有的环境变量。

0

  清除环境变量的方法与清除其他变量的方法一样,都是用 unset 命令,SEHLLSCRIPT 变量清除,清除 SEHLLSCRIPT 变量后,    SEHLLSCRIPT 变量为空,因而 echo $SEHLLSCRIPT 命令输出空白行。

1.4.2、重要的环境变量

  环境变量通常用来存储路径信息,Linux系统及其诸多应用程序的正常运行依赖于某些重要的环境变量的正确设置。

·PWD和OLDPWD

  PWD记录当前的目前路径,当利用cd命令改变当前目录时,系统自动更新PWD的值,OLDPWD记录旧的工作目录,即用户所处的前一个目录。

0

·PATH

  PATH用于帮助Shell找到用户所输入的命令。

  用户所输入的每个命令实际上是一个源代码文件,计算机执行这个文件里的代码以实现这个命令的功能,这些源代码文件称为可执行文件。

  可执行文件存在于各种各样的目录下,一些可执行文件放置在Linux系统标准目录中,还有一些可执行文件可能是用户写的程序或Shell脚本文件,放置在用户目录中。PATH记录了一系列的目录列表,Shell为每个输入命令搜索PATH中的目录列表。

0

  PATH中包含了多个目录的路径,它们之间用冒号分隔,都是以bin或sbin的文件夹结尾,bin或sbin是Linux中存放可执行文件的文件夹。任何在PATH中的可执行文件都可以在Linux系统的任何目录中直接执行。

  若要在PATH中添加新目录,可使用如下命令:

export PATH="/new directory":$PATH

  执行结果如下:

0

·HOME

  HOME记录当前用户的根目录,由/etc/passwd的倒数第2个域决定,HOME目录用于保存用户自己的文件。

0

·SHELL

  SHELL变量保存默认的Shell值,默认的值为/bin/bash,表示当前的Shell是 bash Shell。若有必要用另一个Shell,需要重置SHELL变量值。

·USER 和 UID

  USER 和 UID 是保存用户信息的环境变量,USER表示已登录用户的名字,UID表示已登录用户的ID。

0

·PPID

  PPID是创建当前进程的进程号,即当前进程的父进程号。

1.4.3、环境变量配置文件

  Linux环境变量数量多,不会利用export逐个设置环境变量,而是将export命令放置在特殊的配置文件之中,Shell能够在特定时刻执行这些配置文件,从而自动完成环境变量的配置工作。

  .bash_profile、.bashrc 和 .bash_logout 三个配置文件,皆存在于用户根目录,即$HOME目录,Linux中以 "." 开头的文件为隐藏文件。

  $HOME/.bash_profile是重要的配置文件,当某Linux用户登录时,Shell会自动执行.bash_profile文件,若.bash_profile文件不存在,则自动执行系统默认的配置文件/etc/profile。

0

  .bash_profile文件中定义了该用户的环境变量,可以在已有行后面添加新的行以定义新的环境变量。新加入的行只有注销用户,并再次登录后方可生效。

  若要使新加入的行立即生效,需要利用 source 命令执行 .bash_profile 文件。 source命令也称为 "点命令",即句点符号 "." 和 source 命令是等价的。

  source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。使 .bash_profile 生效可以使用如下两条等价命令:

. .bash_profile
source .bash_profile

  source命令执行脚本和在Shell中执行脚本是有区别的,source在当前bash环境下执行命令,而执行Shell脚本是启动一个子Shell来执行命令。

  若在Shell中直接执行.bash_profile文件,新的环境变量只在子Shell中生效,而无法在当前的Shell中生效。但是,使用 source 命令执行 .bash_profile 后,新环境变量在当前Shell及其子Shell中立即生效。

  bash Shell还支持继承于其他Shell的登录配置文件,bash Shell 和 .bash_login 文件来源于 C Shell的 .login 文件,若它不存在,则查找是否存在.bash_login文件,若它也不存在,则查找是否存在 .profile文件。

  .bash_logout文件在用户注销时执行,用户可以在该文件中写入清除某些环境变量或记录登录时间等命令。

1.4.4、示例

  创建 father.sh、child.sh 脚本,father.sh的脚本内容如下:

#!/bin/bash
# 输出进程号,分别定义本地变量和环境变量,并创建子进程

# 输出父进程号
echo "Father Process ID is $$"

# 定义本地变量并输出
localvar="Define a local variable."
echo "localvar=$localvar"

# 定义环境变量并输出
ENVVAR="Define a environment variable"
export ENVVAR
echo "ENVVAR=$ENVVAR"

# 调用 child.sh 脚本,即创建子进程
$PWD/child.sh

# child.sh 执行完毕,输出相关变量值
echo "Return to father process: $$"
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR"

  father.sh脚本首先打印其进程号,$$表示执行该脚本的进程号。然后,father.sh脚本定义本地变量localvar和环境变量ENVVAR;接着,father.sh放置在同一目录,因此,用环境变量$PWD指明child.sh的目录,若直接调用child.sh,Shell将返回找不到此脚本的错误信息,child.sh执行完毕后,father.sh输出进程号、localvar 和 ENVVAR。

  child.sh的脚本内容如下:

#!/bin/bash
# 该脚本输出自身进程号及其父进程号、重新定义本地变量和环境变量

# 输出自身进程号及其父进程号
echo "Child process ID is $$"
echo "My Father process ID is $PPID"

# 输出本地变量和环境变量的当前值
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR"

# 重新定义本地变量和环境变量
localvar="Redefine this local variable."
ENVVAR="Redefine this environment variable."
echo "localvar=$localvar"
echo "ENVVAR=$ENVVAR" 

  child.sh 脚本输出自身进程号及其父进程号,$$PPID就记录了father.sh的进程号。然后,输出本地变量localvar和环境变量ENVVAR的值;接着,child.sh脚本对localvar和ENVVAR两个变量重新赋值。

  赋予执行权限并执行,执行结果如下:

0

  child.sh输出localvar为空值,这说明本地变量无法传递到子进程,而ENVVAR为father.sh中所赋的值,这说明环境变量对所有的子进程都有效。

  child.sh将localvar和ENVVAR进行了重新赋值,但是,child.sh执行完毕,返回father.sh后,localvar和ENVVAR仍为father.sh中所赋的值,这说明无论是本地变量还是环境变量,都无法向其父进程传递。

1.5、位置参数

  位置参数(positional parameters)是一种特殊的Shell变量,用于从命令行向Shell脚本传递参数,$1表示第1个参数、$2表示第2个参数等,$0为脚本的名字。从${10}开始,参数号需要用花括号括起来,如${10}、${11}、${100}、...。$*和$@一样,表示从$1开始的全部参数。

  新建position.sh脚本,详情如下:

#!/bin/sh
# $0表示脚本本身
echo "The script name is: $0"
echo "Parameter #1:$1"
echo "Parameter #2:$2"
echo "Parameter #3:$3"
echo "Parameter #4:$4"
echo "Parameter #5:$5"
echo "Parameter #6:$6"
echo "Parameter #7:$7"
echo "Parameter #8:$8"
echo "Parameter #9:$9"
# 花括号括起来
echo "Parameter #10:${10}"
echo "-----------------------------"
echo "All the command line parameters are: $*"

  position脚本接收命令行的10个参数,执行结果如下:

0

  特殊位置参数及其意义:

 

特殊位置参数

含义

$#

传递到脚本的参数数量

$*和$@

传递到脚本的所有参数

$$

脚本运行的进程号

$?

命令的退出状态,0表示没有错误,非0表示有错误

  在position脚本中添加特殊位置参数,详情如下:

0

  执行脚本结果:

0

2、引用

  引用指将字符串用引用符号引起来,防止特殊字符被Shell脚本重解释为其他意义,特殊字符是指处理字面意思以外,还可以解释为其他意思的字符,如$字符,可以表示正则表达式的行尾,还可进行变量替换。

0

  如上列出含有 posi 的文件, 被解释为特殊意义;加上引用符号 "", 被解释为字面意义。

  引用是屏蔽特殊字符的特殊意义,而将其解释为字面意义。

  Shell中定义了四种引用符号,详情如下:

 

符号

名称

意义

""

双引号

引用除美元符号($)、反引号(``)、反斜线(\)之外的所有字符

''

单引号

引用所有字符

``

反引号

Shell将反引号中的内容解释为系统命令

\

反斜线

转义符,屏蔽下一个字符的特殊意义

2.1、全部引用和部分引用

  双引号引用除美元符号($)、反引号(`)和反斜线(\)之外的所有字符,即($)、(`) 和 (\)在双引号中仍被解释为特殊意义。

  在双引号中保持$符号的特殊意义可以引用变量,如$variable表示以变量值替换变量名。利用双引号引用变量能防止字符串分割,保留变量中的空格。

  创建 quote.sh脚本,详情如下:

#!/bin/sh
variable=2022
echo $variable
echo "$variable"

variable2="X Y   Z"
echo "$variable2"
echo $variable2

  定义了两个变量 variable 和 variable2,variable为数字2022,variable2为字符串,字符之间用多个空格分开。赋予执行权限,执行结果如下:

0

  对于数值,$variable与"$variable"的值相同;对于由多个空格分开的字符串,"$variable2"打印出了保留多个空格的字符串,$variable2打印出的字符间只用一个空格向分隔。

  双引号引用变量防止字符串分割、保留变量中的空格。

0

  单引号引用所有的字符,即单引号中字符除单引号本身之外都解释为字面意义,单引号不具备引用变量的功能,通常将单引号的引用方式称为全引用,将双引号的引用方式称为部分引用。

2.2、命令替换

  命令替换是指命令的标准输出作为值赋给某个变量,bash Shell定义了两种语法进行命令替换,一种是使用反引号,另一种是利用$(),语法格式如下:

`Linux 命令`
$( Linux 命令 )

2.2.1、反引号

0

  Shell将反引号中的内容解释为系统命令,由于系统没有shell命令,因此返回命令找不到的错误。

  使用反引号进行命令替换时,字符串分割特性依然存在,为说明此特性,分析如下命令:

command `echo`
command "`echo`"
command `echo x y`
command "`echo x y`"

  四条语句的command泛指Linux中的任何命令。

  第(1)条语句echo空字符串,Shell将command命令解析为不带任何参数。

  第(2)条语句将echo空字符串用双引号引起来,双引号有保留控制的作用,因此,Sehll将command命令解析为带了空字符串作为参数。

  第(3)条语句echo产生x和y字符,中间用空格分隔,Shell将command命令解析为带了两个参数x和y,此时echo产生的一个字符串就被解析为两个字符,就造成了字符串分割。

  第(4)条语句,避免字符串分割,只要用双引号将echo命令引起来,Shell将 command 命令解析为带了一个参数 "x y"

  bash Shell产生字符串分割的原因:bash Shell的IFS默认值为空,即bash Shell默认为空格是一个参数的结束符。

  当命令返回有多行结果时,不引用命令替换的结果,换行符将被删除。

0

  第1个命令定义dirlist为 ll f*命令的执行结果,有多个文件信息行组合成;

  第2个命令不引用dirlist,结果显示 dirlist 中的换行符被删除;

  第3个命令引用dirlist时,结果保留了dirlist的换行符。

2.2.2、$()

  尽管$()与反引号在命令替换上是等价的,但$()形式的命令替换可以嵌套。

0

  计算stephane.sh文件中第2行文本的长度,expr length是计算字符串长度的命令,该命令所计算的字符串嵌套$()格式的命令替换,所替换的命令是一个sed目录。

  bash Shell中,反引号与$()在处理双反斜线符号时存在区别,反斜线符号时转义符。

0

  反引号将反斜线符号处理为空格,$()符号将其处理为单斜线符。

2.3、转义

  反斜线符号(\)表示转义,当反斜线后面的一个字符具有特殊意义时,反斜线将屏蔽一个字符的特殊意义,而以字面意义解析它。

  特殊字符既包括正则表达式中定义的元字符,也包括Shell重定向、管道命令中的一些特殊字符。

  Shell中所有的特殊字符及其含义:

特殊字符

含义

&

传递到脚本的参数数量

*

0个或多个在*字符之前的那个普通字符

+

匹配1个或多个在其之前的那个普通字符

^

匹配行首,或后面字符的非

$

命令的退出状态,0表示没有错误,非0表示有错误

`

反引号,Shell引用符号

"

双引号,Shell引用符号

|

管道符号或表示"或"意义

?

匹配0个或1个在其之前的那个普通字符

\

转义符

  转义字符屏蔽字符的特殊意义,示例如下:

0

  转移字符将双引号与美元符号转义后,Shell按字面含义解析转义后字符。

0

  转义字符可以将其本身转义,但是,当Shell命令行或变量赋值遇到单个转义字符时,将出现二级提示符,继续接收Shell输入,而  当脚本中出现单个转义符是,将出错。因此。在Shell编程中,需要了解脚本中每个转义符的作用,避免由单个转义符带来的错误。

  新建 weirdvars.sh 脚本,详情如下:

#!/bin/bash

# 变量赋值
variable="{}\\{}\$\""
echo $variable
echo "$variable"

# 分隔符改为转义符
IFS='\'
echo $variable
echo "$variable"

exit 0

  执行结果如下:

0

  将一串符号赋给变量variable,其中包含四个转义符,第1个转义符将第2个转义符转义,第3、4个转义符分别将 $ 和 " 符号转移,得出结果为 ()\{}$,此时echo "$variable" 和 echo $variable 没有区别。

  利用环境变量将Shell域分隔符改为转义符,echo $variable 得到的结果为:{} {}$",\符号变为了空格,因为Shell根据域分隔符将 $variable 解析为两个域:() 和 {}$",中间用空格分隔。由于双引号具有防止变量分割的作用,因此,echo "$variable"的输出结果仍为:{}{}$"。

  转移字符除了屏蔽特殊字符的特殊意义外,后跟上一些字母能表达特殊含义:

 

符号

含义

\n

新的一行

\r

返回

\t

表示Tab键

\v 或 \f

换行但光标仍旧停留在原来的位置

\b

退格键(Backspace)

\a

发出警报声

\0xx

ASCII码0xx所对应的字符

  echo命令,加上 -e 选项,Shell才会解释特殊符号:

0

  echo不加 -e 选项,Shell按字面含义解释这些特殊字符,按原样输出\t\n\a\v等字符。带上 -e 选项的 echo 命令输出这些字符,Shell将这些字符解释为特殊的含义。

0

  $'' 符号将特殊字符引起来,这些字符可以解释为特殊的含义,$''还可以用于变量赋值,变量值以 $''中符号的特殊意义进行替换。

0

 

posted @ 2023-10-13 20:55  无虑的小猪  阅读(309)  评论(0编辑  收藏  举报