我知道以前可能有人问过这个问题,但我无法通过谷歌找到它。
给定
- Linux内核
- 没有更改 $HOME 的配置
- 巴什
会~ == $HOME
是真的吗?
答案1
需要理解的重要一点是,~
扩展是 shell(某些 shell)的一个功能,它并不是一个神奇的字符,而是指无论在何处使用它的主目录。
它被扩展(通过 shell,这是一个用于解释命令行的应用程序),就像$var
在执行命令之前在 shell 命令行中使用时在某些条件下扩展为其值一样。
该功能首次出现在 20 世纪 70 年代末的 C-shell 中(Bourne shell 没有它,它的前身 Thompson shell 也没有),后来被添加到 Korn shell(在 Bourne shell 上构建的较新 shell)。 80 年代)。它最终由 POSIX 标准化,现在可在大多数 shell 中使用,包括非 POSIX shell,例如fish
.
由于它在 shell 中广泛使用,因此一些非 shell 应用程序也将其识别为主目录。这是许多应用程序的配置文件或应用程序的情况自己的命令行 (mutt
,slrn
,vim
...)。
bash
具体来说(它是 GNU 项目的 shell,广泛用于许多基于 Linux 的操作系统),当作为 调用时sh
,大多数遵循POSIX 规则关于~
扩展,以及 POSIX 未指定的区域,其行为大多类似于 Korn shell(它是 Korn shell 的一部分克隆)。
虽然$var
在大多数地方都进行了扩展(单引号内除外),~
但事后的扩展仅在少数特定条件下进行扩展。
当在列表上下文中、在需要字符串的上下文中使用其自己的参数时,它会被扩展。
以下是它的扩展位置的几个示例bash
:
cmd arg ~ other arg
var=~
var=x:~:x
(POSIX 要求,用于变量,如PATH
,MANPATH
...)for i in ~
[[ ~ = text ]]
[[ text = ~ ]]
(AT&T 中的扩展~
被视为一种模式,ksh
但bash
自 4.0 起不再有)。case ~ in ~) ...
${var#~}
(尽管在其他一些 shell 中没有)cmd foo=~
(尽管不是在调用为 时sh
,并且仅当 左侧的=
形状像不带引号的bash
变量名时)cmd ~/x
(显然 POSIX 要求)cmd ~:x
(但不是x:~:x
或x-~-x
)a[~]=foo; echo "${a[~]} $((a[~]))"
(不在其他一些 shell 中)
以下是一些未扩展的示例:
echo "~" '~'
echo ~@ ~~
(另请注意,这~u
意味着扩展到用户的主目录u
)。echo @~
(( HOME == ~ ))
,$(( var + ~ ))
- 与
extglob
:(case $var in @(~|other))...
虽然case $var in ~|other)
没问题)。 ./configure --prefix=~
(因为--prefix
不是有效的变量名)cmd "foo"=~
(在 中bash
,因为引号)。- 当调用为
sh
:export "foo"=~
,env JAVA_HOME=~ cmd
...
至于它扩展的内容:~
单独扩展为变量的内容HOME
,或者当未设置变量时,扩展为帐户数据库中当前用户的主目录(作为扩展,因为 POSIX 未定义该行为)。
应该注意的是,在 ksh88 和bash
4.0 之前的版本中,波浪号扩展在列表上下文中进行了通配(文件名生成):
$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~
在通常情况下这应该不是问题。
请注意,由于它是扩展的,因此与其他形式的扩展相同的警告也适用。
cd ~
$HOME
如果以组件开头-
或包含组件则不起作用..
。因此,尽管它不太可能产生任何影响,但严格来说,我们应该写:
cd -P -- ~
甚至:
case ~ in
(/*) cd -P ~;;
(*) d=~; cd -P "./$d";;
esac
(覆盖$HOME
类似-
, +2
... 的值)或简单地:
cd
(cd
带你到你的主目录,没有任何参数)
其他 shell 有更高级的~
扩展。例如,在 中zsh
,我们有:
~4
,~-
,~-2
(完成后)用于扩展目录堆栈中的目录(cd
之前所在的位置)。- 动态命名目录。您可以定义自己的机制来决定如何
~something
扩展。
答案2
在任何系统上的任何版本的 Bash 中,是的。~
作为一个术语本身被定义为扩展为:
$HOME 的值
所以它总是与$HOME
当前 shell 的内容相同。还有其他几种波浪线扩展,例如~user
foruser
的主目录,但单个未加引号~
的波浪线扩展始终会扩展为"$HOME"
.
请注意,行为of~
和$HOME
在某些情况下可能不同:特别是,如果$HOME
包含空格(或其他IFS个字符),那么$HOME
(不带引号)将扩展到多个单词,而~
始终是单个单词。~
等价于"$HOME"
(引用)展开。
关于你的具体问题:
[[ $HOME == ~ ]]
总是正确的,因为[[
压制分词。[[ ~ == $HOME ]
可能不会 如果HOME
有模式匹配其中的字符,但[[ ~ == "$HOME" ]]
(即引用"$HOME"
)始终为真。对于HOME
包含空格或特殊字符的值,在单括号内使用它可能会出现语法错误。对于任何合理的主目录配置~
, 和"$HOME"
都是相同的并且比较相等。
Stéphane Chazelas 在评论中指出了一个案例,其中~
和$HOME
给出了不同的值:如果您unset HOME
,那么当你使用~
Bash 时会调用getpwuid
从密码数据库中读取值。这种情况被排除在您没有更改配置的条件之外$HOME
,但为了完整起见,我将在此处提及它。