在linux中写bash脚本,最常用到的判断符号有中括号 [ ] 。看了鸟哥基本篇学习了一下,有一些疑惑,最后通过自己做些代码测试,得出了一些可能的解释,作为学习记录,还在学习中,解释可能不全面甚至错误。
书中有个例子:
name="VBird Tsai"
[ $name == "VBird" ]
直接运行会报错bash:[: too many arguments
鸟哥的解释是当$name没有用双引号括起来,命令[ $name == “VBird” ]就变成了[ VBird Tsai == “VBird” ],VBird和Tsai就变成了两个字符串参数,而 [ ] 只能比较两个参数。
但是,我按这个理解,觉得有点奇怪,我之前运行过
name="abc'abc";echo $name
echo abc'abc
结果很显然不是一样,第一行代码能正常跑。然而第二行代码因为有明显的语法错误,就报错了,这怎么解释,难道说鸟哥那个替换操作,只适用 [ ] 而不适用一些其他的操作像echo。
然后我根据自己经验得出一个猜想:
对于上述代码echo $name,我将shell的解释过程理解如下:
- shell读取上述字符串,以空格截断出第一部分echo作为命令
- 然后截出$name并经过shell解释后得到 abc’abc作为参数 ,然而这个解释后的abc’abc是直接作为字符串,传递给echo的。
所以这样没啥问题,但是对于命令echo abc’abc,它的这个abc’abc需要先经过shell解释,然而明显这个abc’abc里头有个 ‘ 是shell的特殊字符,它不完整,所以shell无法解释而报错,这里有个有趣的地方,仔细看会发现上面的报错信息为-bash:…,也就是说这个报错信息来自bash,而非echo,这样就和我的猜想互证。
但是这似乎还是不能解释鸟哥的那个例子,鸟哥的那个例子似乎给我一种感觉,那个$name被解释后的VBird Tsai中的空格似乎又被shell解释了一次,也就是解释成了把VBird Tsai当成两个字符串,然后我本着这种感觉,写了个脚本aa.sh做测试:
#!/bin/bash
#打印输入的第一个参数
echo "first param is : $2"
# 打印输入参数的个数
echo "param num is : $#"
exit 0
然后运行
name="abc abc abc"
./aa.sh $name
这个命令,乍一看只有一个参数啊,就是name这个字符串变量,但是运行的结果竟然是first param is : abc,param num is : 3,也就是说和我猜想一样,$name被解释成abc abc abc后,中间的空格又被“再次解释”成分隔,而不是将abc abc abc当成一个整的字符串。
后来发现似乎所有的通配符也都会被“再次解释”,下面的例子shell就将 * 再次解释称了目录下的所有文件
鸟哥的例子和我第二个例子似乎都在说“就是直接替换”,但是我第一个例子却告诉我不能直接替换,奇怪,到这我已经成功把自己绕晕。
当然,上面这些都可以通过外加双引号,也就是"$name"的形式避免,这种形式只会被当成一个参数,也就是一个字符串。
猜想性结论
当用 $变量名 来取值时,如果变量中含有空格或通配符,那它们会被shell再次解释,空格被解释成分隔,空字符串被再次解释成“啥都没有”。通过加上额外的双引号,即"$变量名"可以避免被再次解释
另外,看了网上一些文章,很多人认为echo打印字符串时会将连续空格只打印成一个,我觉得不然,他们说的情况应该是指直接echo $字符串变量名,就像我总结的,这样shell会把字符串按空格分成几个字符串,而echo是支持输入多个参数打印的,而刚好多个打印的参数echo是用一个空格隔开,这点有些误解,不信可以echo "$字符串变量名“ 这样打印,就能打出连续空格了。