〜总是等于$ HOME


40

我知道这可能是以前问过的,但是我在Google找不到。

给定

  • Linux内核
  • 没有可更改$ HOME的配置
  • 重击

~ == $HOME是真的吗?


3
我相信是这样,但这不是特定于Linux的问题。相反,我相信~它将等同$HOME于任何POSIX环境。但我可能是错的。
HalosGhost 2014年

4
尽管有以下答案,但并非总是如此。比较echo "~"echo "$HOME"
Sparhawk

@Sparhawk等待,所以1 + 1 不是 2?这是一个阴谋!政府对我们隐藏了一些东西!:P
门把手2014年

1
@Sparhawk,您会发现OP实际上未引用~$HOME。:P
HalosGhost 2014年

2
@HalosGhost啊,好点。(此外,我后来注意到,迈克尔·荷马的答案提到了“一个未引用的单词~”。)无论如何,对于像我这样的随便的读者来说,要记住一些事情。
Sparhawk

Answers:


46

需要理解的重要一点是,~扩展是Shell(在某些Shell中)的功能,它不是魔术字符,而意味着它在任何位置都使用了主目录。

它被扩展(由外壳程序(用于解释命令行的应用程序)),就像$var在执行命令之前在外壳程序命令行中使用某些情况下,将其扩展到其值一样。

该功能最初出现在1970年代后期的C壳中(Bourne壳没有它,或者它的前身Thompson壳也没有),后来又被添加到Korn壳中(在Bourne壳的基础上建立了一个更新的壳) 80年代)。最终它由POSIX进行了标准化,现在可在包括非POSIX的大多数shell中使用fish

由于它在shell中的使用如此广泛,因此某些非shell应用程序也将其视为主目录。这是许多应用的情况下,它们的配置文件或他们自己的命令行(muttslrnvim...)。

bash特别是(它是GNU项目的外壳,并在许多基于Linux的操作系统中广泛使用),当调用为时sh,主要遵循POSIX有关~扩展的规则,并且在POSIX未指定的区域中,其行为与Korn shell(of它是部分克隆)。

尽管$var在大多数地方都进行了扩展(单引号内除外),~但事后才想到扩展仅在某些特定条件下才扩展。

在列表上下文中(在需要字符串的情况下)使用自己的参数扩展时。

以下是一些扩展示例bash

  • cmd arg ~ other arg
  • var=~
  • var=x:~:x(由POSIX要求,用于变量一样PATHMANPATH...)
  • for i in ~
  • [[ ~ = text ]]
  • [[ text = ~ ]]~在AT&T 中被视为一种模式的扩展,ksh但从bash4.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是为了扩展到user的主目录u)。
  • echo @~
  • (( HOME == ~ ))$(( var + ~ ))
  • extglob:(case $var in @(~|other))...虽然case $var in ~|other)可以)。
  • ./configure --prefix=~(因为--prefix不是有效的变量名)
  • cmd "foo"=~(在中bash,由于引号)。
  • 当调用为shexport "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

(以覆盖$HOMElike -+2...的值)或简单地:

cd

(因为cd无需任何参数即可将您转到主目录)

其他外壳具有更高级的~扩展。例如,在中zsh,我们有:

  • ~4~-~-2(竣工)用于扩大在目录栈目录(您已获得的地方cd到前)。
  • 动态命名目录。您可以定义自己的机制来决定如何~something扩展。

25

在任何系统上的任何版本的Bash中,yes~单独定义的术语扩展为:

$ HOME的值

因此它将始终$HOME与当前shell相同。还有其他几个波浪号扩展名,例如~userfor user的主目录,但单引号~本身总是会扩展为"$HOME"

需要注意的是该行为~,并$HOME在某些情况下是不同的:尤其是,如果$HOME包含空格(或其他IFS字符),然后$HOME(不带引号)将扩大到多个字,而~始终是一个字。~等效于"$HOME"(引用)扩展。

关于您的特定问题:

[[ $HOME == ~ ]]

总是正确的,因为[[ 抑制了单词拆分。[[ ~ == $HOME ]可能不是,如果HOME模式匹配在里面的人物,但[[ ~ == "$HOME" ]](即引用"$HOME")始终是真实的。对于HOME包含空格或特殊字符的值,在单括号内使用它可能是语法错误。对于任何明智的主目录配置~"$HOME"它们都是相同的,并且比较相等。


StéphaneChazelas在注释中提到了一种情况,其中~$HOME提供了不同的值:如果您使用unset HOME,那么当您使用~Bash时,它将调用getpwuid从密码数据库中读取一个值。您无需更改配置的情况就排除了这种情况$HOME,但出于完整性考虑,我在这里将其提及。


1
但是,/bin/sh可能不是bash。我不知道,Posix的sh规范讲述~
巴西莱Starynkevitch

1
POSIX指定~~不在Thomson或Bourne外壳中(当时可作为/bin/sh)。这不是在rc或其衍生物(使用它的其他东西)
斯特凡Chazelas

5
在包括在内的一些shell中bash,如果HOME未设置,~则从passwd数据库扩展到用户的主目录。因此,这种情况下~可能无法扩展为的值$HOME
斯特凡Chazelas

1
请注意,bash在bash4用来在波浪号扩展上执行glob之前(try HOME='/*' bash -c 'echo /*')。因此HOME=/*; [ "$HOME" = ~ ]会在那里返回错误。
斯特凡Chazelas

4
@cuonglm我检查了源代码。它最终会 调用 get_current_user_info,它会在Tandem之外的所有平台使用getpwuid
迈克尔·荷马,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.