壳如何知道家?

Lot*_*oLo 25 bash tcsh cd-command csh home

每个 shell 都有一个环境变量 $HOME 集(例如:)/Users/lotolo。如果我在 csh 下,我可以unsetenv HOME,如果我这样做,cd我会在家里。我也在 bash ( unset HOME)上对此进行了测试,它的行为是相同的。那么 shell 如何知道 my/other_user 的家在哪里呢?它在哪里读取这些值?

这不是重复的,因为我的问题不是如何知道,而是shell如何知道HOME. 这种行为也扩展到其他用户。

Sté*_*las 33

cshand的情况下tcsh,它记录了$HOMEshell 启动时变量的值($home@JdeBP 所指出的变量中)。

如果您在开始之前取消设置csh,您将看到如下内容:

$ (unset HOME; csh -c cd)
cd: No home directory.
Run Code Online (Sandbox Code Playgroud)

对于bash(以及大多数其他类似 Bourne 的 shell),我看到了与您不同的行为。

bash-4.4$ unset HOME; cd
bash: cd: HOME not set
Run Code Online (Sandbox Code Playgroud)

$HOME变量的内容由登录过程根据存储在用户数据库中的信息与您的用户名进行初始化。

有关用户名本身的信息并不总是可用的。shell 所能确定的只是正在执行它的进程的用户 ID,并且多个用户(具有不同的主目录)可以共享相同的用户 ID。

因此,一旦$HOME消失,就没有可靠的方法将其取回。

查询与getpwxxx()运行 shell 的用户具有相同 uid 的第一个用户的主目录的用户数据库(使用标准 API)只是一个近似值(更不用说用户数据库可能已更改的事实(或主目录)目录被定义为一次性值),因为登录会话开始)。

zsh 是我所知道的唯一能做到这一点的外壳:

$ env -u HOME ltrace -e getpw\* zsh -c 'cd && pwd'
zsh->getpwuid(1000, 0x496feb, 114, 0x7f9599004697)      = 0x7f95992fddc0
/home/chazelas
+++ exited (status 0) +++
Run Code Online (Sandbox Code Playgroud)

我尝试过的所有其他 shell 要么抱怨未设置 HOME,要么/用作默认 home 值。

然而,一个不同的行为是fish's,它似乎查询数据库中存储的用户名($USER如果有的话)或者getpwuid()如果没有则执行:

$ env -u HOME USER=bin ltrace -e getpw\* fish -c 'cd;pwd'
fish->getpwnam("bin")  = 0x7fd2beba3d80
fish: Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory
where the current user has write access.
fish: Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory
where the current user has write access.
--- SIGCHLD (Child exited) ---
/bin
+++ exited (status 0) +++


$ env -u HOME -u USER ltrace -e getpw\* fish -c 'cd;pwd'
fish->getpwuid(1000, 0x7f529eb4fb28, 0x12d8790, 0x7f529e858697) = 0x7f529eb51dc0
fish->getpwnam("chazelas")                                      = 0x7f529eb51d80
--- SIGCHLD (Child exited) ---
--- SIGCHLD (Child exited) ---
/home/chazelas
+++ exited (status 0) +++
Run Code Online (Sandbox Code Playgroud)

当用户不存在时的 SEGV ( https://github.com/fish-shell/fish-shell/issues/3599 ):

$ env -u HOME USER=foo fish -c ''
zsh: segmentation fault  env -u HOME USER=foo fish -c ''
Run Code Online (Sandbox Code Playgroud)

  • 我想我们可以报告这个问题!顺便说一句,非常好的答案,谢谢! (2认同)

Jde*_*eBP 7

那么 shell 如何知道 my/other_user 的家在哪里呢?

它没有。你只是没有正确地进行实验。正如您从 C shell 手册中看到的,如果不提供参数,该cd命令将更改为home变量的值。如果未设置此变量,则它不知道将目录更改到何处并打印错误:

机器:~> 设置主页=/
机器:/家/用户> cd
机器:~> 未设置主页
机器:/> cd
cd:没有主目录
机器:/> 

您取消了错误的变量设置。它不是HOME,环境变量,它是homeC shell 的内部变量(在 shell 启动时从前者的值初始化,否则本身就是一个独立变量)。