我知道这可能是以前问过的,但是我在Google找不到。
给定
- Linux内核
- 没有可更改$ HOME的配置
- 重击
会~ == $HOME
是真的吗?
echo "~"
和echo "$HOME"
。
~
或$HOME
。:P
我知道这可能是以前问过的,但是我在Google找不到。
给定
会~ == $HOME
是真的吗?
echo "~"
和echo "$HOME"
。
~
或$HOME
。:P
Answers:
需要理解的重要一点是,~
扩展是Shell(在某些Shell中)的功能,它不是魔术字符,而意味着它在任何位置都使用了主目录。
它被扩展(由外壳程序(用于解释命令行的应用程序)),就像$var
在执行命令之前在外壳程序命令行中使用某些情况下,将其扩展到其值一样。
该功能最初出现在1970年代后期的C壳中(Bourne壳没有它,或者它的前身Thompson壳也没有),后来又被添加到Korn壳中(在Bourne壳的基础上建立了一个更新的壳) 80年代)。最终它由POSIX进行了标准化,现在可在包括非POSIX的大多数shell中使用fish
。
由于它在shell中的使用如此广泛,因此某些非shell应用程序也将其视为主目录。这是许多应用的情况下,它们的配置文件或他们自己的命令行(mutt
,slrn
,vim
...)。
bash
特别是(它是GNU项目的外壳,并在许多基于Linux的操作系统中广泛使用),当调用为时sh
,主要遵循POSIX有关~
扩展的规则,并且在POSIX未指定的区域中,其行为与Korn shell(of它是部分克隆)。
尽管$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
是为了扩展到user的主目录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
like -
,+2
...的值)或简单地:
cd
(因为cd
无需任何参数即可将您转到主目录)
其他外壳具有更高级的~
扩展。例如,在中zsh
,我们有:
~4
,~-
,~-2
(竣工)用于扩大在目录栈目录(您已获得的地方cd
到前)。~something
扩展。在任何系统上的任何版本的Bash中,yes。~
单独定义的术语扩展为:
$ HOME的值
因此它将始终$HOME
与当前shell相同。还有其他几个波浪号扩展名,例如~user
for user
的主目录,但单引号~
本身总是会扩展为"$HOME"
。
需要注意的是该行为的~
,并$HOME
在某些情况下是不同的:尤其是,如果$HOME
包含空格(或其他IFS字符),然后$HOME
(不带引号)将扩大到多个字,而~
始终是一个字。~
等效于"$HOME"
(引用)扩展。
关于您的特定问题:
[[ $HOME == ~ ]]
总是正确的,因为[[
抑制了单词拆分。[[ ~ == $HOME ]
可能不是,如果HOME
有模式匹配在里面的人物,但[[ ~ == "$HOME" ]]
(即引用"$HOME"
)始终是真实的。对于HOME
包含空格或特殊字符的值,在单括号内使用它可能是语法错误。对于任何明智的主目录配置~
,"$HOME"
它们都是相同的,并且比较相等。
StéphaneChazelas在注释中提到了一种情况,其中~
并$HOME
提供了不同的值:如果您使用unset HOME
,那么当您使用~
Bash时,它将调用getpwuid
从密码数据库中读取一个值。您无需更改配置的情况就排除了这种情况$HOME
,但出于完整性考虑,我在这里将其提及。
/bin/sh
可能不是bash
。我不知道,Posix的sh
规范讲述~
~
。~
不在Thomson或Bourne外壳中(当时可作为/bin/sh
)。这不是在rc
或其衍生物(使用它的其他东西)
bash
,如果HOME
未设置,~
则从passwd数据库扩展到用户的主目录。因此,这种情况下~
可能无法扩展为的值$HOME
。
bash
在bash4用来在波浪号扩展上执行glob之前(try HOME='/*' bash -c 'echo /*'
)。因此HOME=/*; [ "$HOME" = ~ ]
会在那里返回错误。
~
它将等同$HOME
于任何POSIX环境。但我可能是错的。