当用作路径的前缀时,〜(波浪号)是什么?

R.D*_*.D. 12 command-line osx

编辑:这是/sf/ask/69903851/的副本。我没有将这个问题作为重复来关闭的声誉。

我不是指~主目录中的 as,而是指:

$ ls ~foo/bar
/some/mount/point/foo/bar
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试使用不同的挂载点,例如:

$ mount | ag "/dev "
devfs on /dev (devfs, local, nobrowse)
$ ls /dev/stdin
/dev/stdin
$ ls ~stdin
zsh: no such user or named directory: stdin . 
# bash has a similar error message: 
ls: ~stdin: No such file or directory
Run Code Online (Sandbox Code Playgroud)

~在这种情况下称为什么?它是如何工作的?

编辑:基于以下一些评论的更多信息:

  1. 我可以证明这foo不是我系统上的用户名。
  2. 尝试自动完成时,ls -lah ~并非显示所有选项。即我能够cd ~qux,当qux没有出现在自动完成时。再次qux不是我系统中的用户。
  3. 如果重要的/some/mount/point是网络共享。
  4. 所有细节都暗示了一些命名路径混乱,这是路径名扩展的 Z shell 功能,但这也适用于 bash,它显然不支持 Z shell 的命名路径之类的东西。

Ser*_*nyy 15

什么是~foo

从引用的bash手册(与强调):

如果单词以未加引号的波浪号字符 (`~') 开头,则第一个未加引号的斜杠之前的所有字符(或所有字符,如果没有未加引号的斜杠)都被视为波浪号前缀。如果波浪号前缀被引用,波浪号后面的波浪号前缀中的字符被视为可能的登录名。

~foofoo完全按照 中指定的方式 扩展到用户的主目录/etc/passwd。请注意,这可以包括系统用户名;这并不一定意味着人类用户或他们实际上可以在本地登录(例如,他们可以通过 SSH 密钥登录)。

事实上,如评论中所述,bash将使用getpwnam函数。该函数本身由POSIX标准指定,因此应该存在于大多数类 Unix 系统上,包括macOS X。此功能不仅限于/etc/passwd搜索其他数据库,例如 LDAP 和 NIS。从特定摘录bash 源代码tilde.c文件,开始于行394:

  /* No preexpansion hook, or the preexpansion hook failed.  Look in the
     password database. */
  dirname = (char *)NULL;
#if defined (HAVE_GETPWNAM)
  user_entry = getpwnam (username);
#else
  user_entry = 0;
Run Code Online (Sandbox Code Playgroud)

实际例子

您可以在下面看到在我的系统上使用系统用户名进行的测试。注意对应的passwd入口和结果ls ~username

$ grep '_apt' /etc/passwd
_apt:x:104:65534::/nonexistent:/bin/false
$ ls ~_apt
ls: cannot access '/nonexistent': No such file or directory
$ grep '^lp' /etc/passwd
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
$ ls ~lp
ls: cannot access '/var/spool/lpd': No such file or directory
Run Code Online (Sandbox Code Playgroud)

例如,即使_apt帐户按照输出的建议被锁定,passwd -S apt它仍然显示为可能的登录名:

_apt L 11/29/2017 0 99999 7 -1
Run Code Online (Sandbox Code Playgroud)

请注意:这不是 macOS 特定的功能,而是特定于 shell 的功能。

  • 您可以使用 `getent passwd foo` 而不是 `grep foo /etc/password` 来遵循与 shell 相同的查找机制——可能包括@Abigail 提到的基于网络的目录服务。 (2认同)

WEB*_*uju 6

在为什么你看到的东西总结~foo/bar,那是因为你有一个名为用户foo用命名的文件夹在系统上bar他们的主目录。

在另一个社区中查看此解决方案,该解决方案解释了为什么 (波浪号)~不仅仅是“主目录”。

如果您bin的系统上有一个用户名,那么您可以通过以下命令列出bin 主目录的内容:

ls ~bin

您可以尝试的另一件事是在提示下键入以下内容后使用 Tab 补全(不要回车,只需使用 Tab 键):

ls -lah ~ tab

以查看用户的主目录列表,~如果您继续,这些目录将扩展到。选项卡完成的示例(截断)输出ls -lah ~ tab

$ ls -lah ~ [tab]
~antman/            ~games/
~bin/               ~mail/
Run Code Online (Sandbox Code Playgroud)

  • 感谢有关 bash 完成的提示——产生了一些有趣的自动完成结果。虽然 `~foo` 做了自动完成,我可以证明 `foo` 不是我系统上的用户(并且确实不存在于 `/etc/passwd` 中)。此外,`/some/mount/point` 中的所有文件夹/文件都显示在自动完成中,这非常有趣。 (2认同)