为什么波浪号 (~) 不在双引号内展开?

Bra*_*iam 68 shell

根据这个答案和我自己的理解,波浪号扩展到主目录:

$ echo ~
/home/braiam
Run Code Online (Sandbox Code Playgroud)

现在,每当我希望 shell 扩展工作时,即使用诸如 的变量名$FOO,并且不要因为意外的字符、诸如空格等而中断。应该使用双引号"

$ FOO="some string with spaces"
$ BAR="echo $FOO"
$ echo $BAR
echo some string with spaces
Run Code Online (Sandbox Code Playgroud)

为什么这种扩展不适用于波浪号?

$ echo ~/some/path
/home/braiam/some/path
$ echo "~/some/path"
~/some/path
Run Code Online (Sandbox Code Playgroud)

cuo*_*glm 58

原因,因为在双引号内,波浪号~没有特殊含义,它被视为文字。

POSIX 将双引号定义为:

用双引号 ( "" ) 括起来的字符应保留双引号内所有字符的字面值,但美元符号、反引号和反斜杠除外,

...

应用程序应确保双引号前有反斜杠以包含在双引号中。参数“@”在双引号内有特殊含义

除了$, `,\@,其他字符被视为双引号内的文字。

  • 在这种情况下,我想你应该使用`$HOME`。 (14认同)
  • 或者你可以不引用`~`,例如`ls -l ~/"My Documents"` (12认同)
  • @cuonglm:这就像告诉你的孩子,当他们问为什么天空是蓝色的时候,它是蓝色的,因为蓝色波长正在击中他们的视网膜。这是真的,并给出了直接的原因,但有用且令人满意的原因必须更深入才能给出真正的*原因*,而不是长因果链中紧接在前的原因。长链中的初始原因比紧接在前的原因更有用,或者至少进一步给出逻辑原因,而不仅仅是“因为这就是它的工作方式”。 (3认同)
  • 那么,@iconoclast,为什么_是_天蓝色?:) :) :) (3认同)
  • @iconoclast 如果你真的想要“为什么他们以这种方式实现”,请阅读 [Stephane](http://unix.stackexchange.com/a/151967/41104) 答案。 (2认同)

Mic*_*mer 40

POSIX 将波浪号扩展定义为:

“波浪号前缀”由单词开头的未加引号的<波浪号> 字符组成,后跟单词中第一个未加引号的 <斜杠> 之前的所有字符,如果没有 <,则为单词中的所有字符斜线>。在赋值中,可以使用多个波浪号前缀:[...] 跟在赋值的 <equals-sign> 之后,跟在任何未加引号的 <colon> 之后,或者两者都有。[...] 如果没有引用波浪号前缀中的任何字符,则将 <波浪号> 后面的波浪号前缀中的字符视为来自用户数据库的可能登录名。[...] 如果登录名为空(即波浪号前缀仅包含波浪号),则波浪号前缀将替换为变量 HOME 的值。如果未设置 HOME,则结果未指定。[...]

所以最短的答案是“因为它是这样定义的”:引用前缀中的任何字符,包括~,抑制扩展。

它还将扩展定义为始终产生单个单词,因此无需引用:

由波浪号扩展产生的路径名应被视为被引用,以防止它被字段拆分和路径名扩展改变。

如果某些路径需要引用,而其余路径是波浪号前缀,您可以直接将波浪号扩展和普通引用结合起来:

$ cat ~/"file name with spaces"
Run Code Online (Sandbox Code Playgroud)

关于更广泛的“为什么”:由于没有可以想象的 word-splitting 用途~,这应该是默认行为,而不是要求它被引用。因为不需要引用它,所以~在引号内赋予特殊含义将是不必要的复杂化。而且,当然,历史原因意味着即使这是可取的,现在也无法更改。


Sté*_*las 27

~ 起源于 C-shell,早在它被添加到 Korn shell 和后来添加到 POSIX shell 规范之前。

在 C-shell 中,~是一个通配符(*.txt例如,由与扩展相同的例程扩展),所以像其他通配符一样,不在双引号内执行。


mel*_*lds 15

虽然这不能回答为什么它是这样设计的,但$HOME如果你需要替换,你可以使用它,因为这本质上就是~这样做的。

$ echo "$HOME/some/path"
/home/braiam/some/path
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于 `~otheruser` (7认同)
  • 是的,但你可以这样做:THEM=~otheruser 然后使用 "$THEM/some/path" (3认同)