语法
shell 波浪线展开,使用起来挺简单的,但是要描述起来还是挺复杂的。因此,本文通过几个例子来快速理解波浪线展开。
cd ~
cd ~/foo
这两个例子中,波浪线被开展为 HOME 环境变量的值,也就说,通过 cd ~ 就可以回到当前用户的家目录,通过 cd ~/foo 就可以切换到当前用户家目录下的foo目录。
cd ~david
cd ~david/foo
这两个例子中,波浪线后有一个单词,而这个单词会被认为是一个登陆名(login name),波浪线加上这一个登陆名,会被展开为这个用户的家目录。也就是说,cd ~david 会切换到用户为 david 的家目录,cd ~david/foo 会切换到用户为 david 的家目录下的 foo 目录。
cd ~+/foo
cd ~-/foo
~+ 会被展开为环境变量 PWD 的值,它表示当前工作目录的路径,那么 cd ~+/foo 就等价于 cd ${PWD}/foo。
~- 会被展开为环境变量 OLDPWD 的值,它表示上一个工作目录的路径。但是,由于我们可能没有切换过工作目录,例如使用 cd 命令 或者 pushd 命令切换工作目录,那么环境变量 OLDPWD 并没有值,这就导致 ~- 不会被展开,保持原义,此时 cd ~-/foo 就会报错。
因此 cd ~-/foo 等价于 cd ${OLDPWD-'~-'}/foo,这里使用了一个 shell 参数开展 ${OLDPWD-'~-'}。它表示如果环境变量 OLDPWD 没有设置,那么就取 '~-' 的值 ( ~- 被单引号括起来,因此保持原义)
。如果环境变量 OLDPWD 被设置过,那么就展开为这个变量的值。
陷阱
波浪线展开最常遇到的陷阱是,把波浪线置于单/双引号内,这是错误的写法,因为单/双引号内都不支持波浪线展开。
单引号中任何字符都保持原义。双引号中有特殊意义的字符只有
$和`和\,$用于参数展开、命令替换、以及算术展开,`用于命令替换,\用于转换特殊字符,例如\$,使$失去特殊意义,保持原义。
记得我第一次进行 shell 脚本实战时,一个错误困扰了我很久,例子如下
if [ -f "~/Bin" ]; then
echo "Bin目录存在"
else
echo "Bin目录不存在"
fi
无论家目录下的Bin目录是否存在,这个脚本执行的结果永远都是 "Bin目录不存在"。
为何是这样呢? 就是因为波浪线展开 ~/Bin 被双引号包围起来了,这就导致了波浪线展开不会被执行,因此 [ -f "~/Bin" ] 这个 test 表达式永远判断的是当前工作目录下,一个名为 ~/Bin 的目录是否存在,那么结果当然是不存在。
所以脚本正确的写法如下
if [ -f ~/Bin ]; then
echo "Bin目录存在"
else
echo "Bin目录不存在"
fi
优先级
波浪线展开在所有的 shell 展开中具有第二优先级,仅次于大括号展开。如果遇到混合使用多个 shell 展开,并且不确定展开顺序,可以查询 Bash手册 。