相关文章
Linux专栏https://blog.csdn.net/weixin_45791458/category_12234591.html
在bash shell中,变量(variable)是参数(parameter)的一类,用于存储值,且变量还可以拥有属性(attributes),这通过bash内建命令declare来完成。
一个存储空字符串的变量被看做是未设置(unset)的变量,可以通过bash内建命令unset将一个已设置的变量转化成未设置的。
给一个变量赋值可以通过下面的命令来完成。
name=[value]
其中的name是一个合法的标识符,由数字、字母和下划线组成,且不能以数字开头。name后面必须紧跟=,不能有空格。如果有空格,则bash会将name解析成一个命令,而后面的=[value]解析为它的参数,这是一个错误。令人遗憾的是,即使用反斜杠\将空格转义,bash依然无法识别name =[value]这样的命令。[value]和=之间可以有空格,但这个空格必须被引号包围或反斜杠转义,否则空格之后的部分会被当做另一个命令名而不是value的一部分(这很有趣,在赋值命令后加其他命令不需要使用;分开,只需要使用空格分开)。value中如果有空格,则也需要使用引号包围或反斜杠转义,原因同理。下面展示了这些性质。
例1
1a=test1
bash: 1a=test1: command not found... //错误,name不能以1开头,否则会被识别为命令名
a =test1
bash: a: command not found... //错误,name和value之间不能有空格,否则name会被单独解析为一个命令名
a\ =test1
bash: a =test1: command not found... //错误,即使转义空格,bash依旧识别不了这种格式
a= test1
bash: test1: command not found... //错误,这会被解析为将空字符串赋值给a,并执行test1命令
a=\ test1 //bash可以解析这种格式的赋值
echo "$a" //使用了双引号"",为的是打印出变量a的值中空格,否则其会被解析为分隔符
test1 //前面有空格
a=" test1" //bash可以解析这种格式的赋值
echo "$a" //使用了双引号"",为的是打印出变量a的值中空格,否则其会被解析为分隔符
test1 //前面有空格
a=te st1
bash: st: command not found... //错误,st会被解析为另一个命令
a=test1 echo $a //这是合法的,echo命令可以正常执行,而无需;分隔
test1
a="te st1" //bash可以解析这种格式的赋值
echo "$a" //使用了双引号"",为的是打印出变量a的值中空格,否则其会被解析为分隔符
te st1 //变量值中有空格
赋值命令中的value在使用前会首先进行拓展(实际上所有命令在解析前都会进行拓展,比如大括号拓展、波浪号拓展、参数(变量)拓展、命令替换、算数拓展、路径拓展等),在这里我们只涉及到简单的变量拓展,就是以name或{name}这种形式出现的拓展,它们两者的区别在于,后者更清晰的体现了变量名字的范围,而前者依赖bash解析到一个不合法的name字符从而确定name的范围。但需要注意的是,name在拓展后不会被解析为赋值语句,下面举例说明这些性质。
例2
a=test1 //给a变量赋值test1
b=$a //这条命令在执行前会先拓展为b=test1
echo $b //这条命令在执行前会先拓展为echo test1
test1
b=$aa //错误,变量拓展是贪婪的,这代表着bash会把aa解析为一个变量名($aa后的换行符不是合法的命名字符),而不是$a再加上a
b=${a}a //这是正确的,因为{}明确指出了参数名的范围,所以参数拓展后为b=test1a
echo $b //这条命令在执行前会先拓展为echo test1a
test1a
c=b
$c=$a //错误,即使name也使用了参数拓展,bash也无法识别这种形式的赋值语句
bash: b=test1: command not found...
例1中还使用了双引号"...",它使得其引用内容中的拓展正常进行(它不会使$失去作用,除此之外还有反引号`和某些条件下的转义符\),但它会使得其引用内容中的一些字符失去其特殊意义(空格、换行符等),只代表其字面意思,例如空格符,bash一般会将其当做分隔命令和其选项、参数的依据,而一个包含在双引号""内的空格符则只代表空格的字面意思。而单引号'...'的作用更加激进,它使得其引用内容的拓展也不进行,字符也都失去其特殊意义。
还有一个需要提到的是转义符\,它能使其后的任何一个字符失去其特殊意义(包括自己),当转义符被包括在双引号中,转义符在其后是$、`、"、\或换行符时保持其转义的能力,否则被当做字面量,例如其后紧跟着双引号或单引号的末尾,则双引号或单引号的末尾被转义,则此时后面还需要一个没有被转义的末尾来结束引用,简单来说就是,如果硬碰硬,则引号会被转义符打败。下面的例3说明了这些性质。
例3
echo hello world //不使用引号,则其hello world前的空格都会被当做分隔符,最终echo获得两个参数hello和world
hello world
echo " hello world" //使用引号,则其hello world前的空格不会被当做分隔符,最终echo获得一个参数" hello world"
hello world
a=test1
echo "$a" //双引号内的拓展可以正常进行,echo命令在执行前被拓展为echo "test1"
test1
echo '$a' //单引号内的拓展不进行,echo命令为其字面意思echo '$a'
$a
echo "te'$a'st" //双引号内可以直接嵌套单引号,此时单引号值表现其字面意思,因此$a的拓展可以进行,拓展为echo "te'test1'st"
te'test1'st
echo \$a //转义符使$失去特殊意义,拓展不进行
$a
echo '$a' //单引号使$失去特殊意义,拓展不进行
$a
echo "\$a" //双引号本应使得转义符\失去特殊意义,但其后是$,因此转义符保持其转义能力$被转义,拓展不进行
$a
echo "\1" //双引号本因转义符\失去特殊意义,只有字面意义
\1