~ 是否始终等于 $HOME

~ 是否始终等于 $HOME

我知道以前可能有人问过这个问题,但我无法通过谷歌找到它。

给定

  • 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 应用程序也将其识别为主目录。这是许多应用程序的配置文件或应用程序的情况自己的命令行 (muttslrnvim...)。

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 中的扩展~被视为一种模式,kshbash自 4.0 起不再有)。
  • case ~ in ~) ...
  • ${var#~}(尽管在其他一些 shell 中没有)
  • cmd foo=~(尽管不是在调用为​​ 时sh,并且仅当 左侧的=形状像不带引号的bash变量名时)
  • cmd ~/x(显然 POSIX 要求)
  • cmd ~:x(但不是x:~:xx-~-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 和bash4.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 的内容相同。还有其他几种波浪线扩展,例如~userforuser的主目录,但单个未加引号~的波浪线扩展始终会扩展为"$HOME".

请注意,行为of~$HOME在某些情况下可能不同:特别是,如果$HOME包含空格(或其他IFS个字符),那么$HOME(不带引号)将扩展到多个单词,而~始终是单个单词。~等价于"$HOME"(引用)展开。

关于你的具体问题:

[[ $HOME == ~ ]]

总是正确的,因为[[ 压制分词。[[ ~ == $HOME ]可能不会 如果HOME模式匹配其中的字符,但[[ ~ == "$HOME" ]](即引用"$HOME")始终为真。对于HOME包含空格或特殊字符的值,在单括号内使用它可能会出现语法错误。对于任何合理的主目录配置~, 和"$HOME"都是相同的并且比较相等。


Stéphane Chazelas 在评论中指出了一个案例,其中~$HOME给出了不同的值:如果您unset HOME,那么当你使用~Bash 时会调用getpwuid从密码数据库中读取值。这种情况被排除在您没有更改配置的条件之外$HOME,但为了完整起见,我将在此处提及它。

相关内容