每一个Linux初学者都肯定会遇到波浪号,并且会迅速的开始使用上波浪号~,来表达从HOME目录开始的路径。那么波浪号的原理是什么呢?

首先,根据Bash变量的定义,它肯定不是变量,因为使用它不需要以$开头,export中也没有,第二,我们也可以看到alias中没有这个别名,第三,显然也不是一个设备
那么,它是通过什么样的方式发生作用的呢?是我们在登录SHELL的时候就注册上了,还是在profile中被注册呢。
通过查阅手册,我很快找到了这个问题的答案:它是一个Bash运行时检查的变量。

如果一个单词以没有被转义过的波浪号~开头,所有截止到/ 前的字符,都会被作为波浪号前缀(tilde-prefix) 字符串进行处理
波浪号前缀有三种类型

波浪号:login name

首先波浪号后面的字符串会被看做是login name
如果有login name,那么替换为login name所在的home目录(后面直接接字母,例如fred)
如果login name为空,那么替换为$HOME变量 (单个的~时)
如果$HOME目录再为空,那么替换为执行shell的用户的home目录
注意到这里是个替换操作
因此,当使用strace追踪对应命令的系统调用,就会发现:

$ strace ls ~
execve("/bin/ls", ["ls", "/home/zhutou"], [/* 23 vars */]) = 0

已经在执行时就被替换成对应的字符串的参数了。

由于规则1,所以~fred/foo,等同于用户fred home目录下的foo子目录

波浪号: PWD和OLDPWD

如果波浪号前缀是”+” ,一个波浪号和一个加号,那么用shell中的变量$PWD替换掉波浪号前缀
例如 ls ~+/foo 等同于 ls $PWD/foo
(哇一个鸡肋操作,岂不也是等同于ls foo嘛)
如果波浪号前缀是”
-“,那么用$OLDPWD 替换之
例如 ls ~-/foo 等同于 ls $OLDPWD/foo ,相当于可以从上一次到达的工作目录开始进行操作

波浪号:数字

如果波浪号前缀的波浪号后面,是一个数字,例如~3,那么这个数字N连带着波浪号前缀,会被替换成dirs调用的结果,N作为dirs的参数

$ dirs
~/work/testmx ~/work ~

在这样的情况下,2等同于/work

作用时机

所有变量赋值的时候,都会检查这个波浪号前缀字符串,比如用于连接的: 字符,以及赋值的等号= ,在这样的场景下,这个扩展同样会发挥作用,因此可以用来给PATH等变量赋值,shell都会做对应的展开

完整的手册如下:
~
The value of $HOME

~/foo
$HOME/foo

~fred/foo
The subdirectory foo of the home directory of the user fred

~+/foo
$PWD/foo

~-/foo
${OLDPWD-‘~-‘}/foo

~N
The string that would be displayed by ‘dirs +N’

~+N
The string that would be displayed by ‘dirs +N’

~-N
The string that would be displayed by ‘dirs -N’

参考文献:
[1]、Bash Reference Manual: Tilde Expansion