bash中的波浪线扩展

扩展触发条件

如果一个token以波浪线~开头,以第一个没有被转义或者引用的斜杠/token的末尾结束,且中途的字符都没有被引用,那这一段称为波浪线前缀tilde prefix,在波浪线前缀中不包含波浪线和斜杠的部分在波浪线扩展中被称之为登录名login name

1
2
3
4
5
6
7
8
~     #登录名为空
~root #登录名为root
~foo #登录名为foo
~foo/tmp # 登录名为foo
~foo/'t'mp #登录名为foo
a~foo #不扩展,token没有以波浪线开头
~\foo #不扩展,因反斜杠不存在波浪线前缀
~f'o'o #不扩展,因引用不存在波浪线前缀

扩展行为

波浪线前缀会被扩展为登录名所在用户的家目录,如果登录名为空则扩展为当下shell的$HOME即当下用户的家目录。如果登录名所代表的用户不存在,则波浪线前缀保持不变

1
2
3
4
5
echo ~root/tmp
echo ~foo/tmp #没有foo用户
# 输出
# /root/tmp
# ~foo/tmp

如果登录名为+,波浪线前缀会被扩展为$PWD,如果登录名为-,波浪线前缀会被扩展为$OLDPWD$OLDPWD没有被设置则波浪线前缀保持不变。

1
2
3
4
5
6
7
8
9
10
echo ~- #此时shell的$OLDPWD未被设置
cd ~
cd /tmp
echo ~+
echo ~-

# 输出
# ~-
# /tmp
# /root

如果登录名为+NN,波浪线前缀会被扩展为从目录栈DIRSTACK从栈顶往下第N个目录值,如果登录名为-N则为从栈底往上第N个目录值,N从0开始,如果这个目录值不存在,则波浪线前缀保持不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
cd /tmp
mkdir dir{0..2} 2>/dev/null
while [ $? -eq 0 ]; do
popd 2>&1 2>/dev/null
done
for dir_name in dir{0..2}; do
cd $dir_name
pushd ../ 2>&1 >/dev/null
done
printf "%s\n" "${DIRSTACK[@]}"
echo
printf "%s\n" ~{0..3}
echo
printf "%s\n" ~+{0..3}
echo
printf "%s\n" ~-{0..3}
echo
printf "%s\n" ~+4

# 输出
# /tmp
# /tmp/dir2
# /tmp/dir1
# /tmp/dir0

# /tmp
# /tmp/dir2
# /tmp/dir1
# /tmp/dir0

# /tmp
# /tmp/dir2
# /tmp/dir1
# /tmp/dir0

# /tmp/dir0
# /tmp/dir1
# /tmp/dir2
# /tmp

# ~+4