我使用的是 Fedora,其中所有预装的 shell 显然都支持 bashism:bash --posix
确实如此,甚至如此sh
。不过,当我使用这个函数时,
pathprepend () {
if [[ ":$PATH:" != *":$1:"* ]]; then
PATH="$1${PATH:+":$PATH"}"
fi
}
PATH
从向添加目录~/.profile
,Git 没有发现它。请注意,echo $PATH
在我使用 Git 的 bash 会话中,确实列出了我的目录,我注意到,只是因为我使用了diff-highlight
,所以在该目录中建立了符号链接,而在我开始使用上述pathprepend
函数后,Git 抱怨diff-highlight
缺少了该功能。恢复 POSIX 兼容PATH
设置后,它恢复正常工作。
这让我想知道程序使用什么来读取它们的环境。它们是否都带有自己的机制来执行此操作?它们是否将工作留给某个系统 shell 或库?
编辑
@Bodo,这是我以前常做的~/.profile
:
pathprepend () {
if [[ ":$PATH:" != *":$1:"* ]]; then
PATH="$1${PATH:+":$PATH"}"
fi
}
pathprepend "$HOME/.local/bin"
我说的“POSIX 兼容”是指没有任何暴力倾向。这是我现在所拥有的~/.profile
:
pathprepend () {
case ":$PATH:" in
*":$1:"*)
:;;
*)
PATH="$1${PATH:+":$PATH"}";;
esac
}
pathprepend "$HOME/.local/bin"
两种情况下均~/.profile
来源于~/.bash_profile
,其中包含
# Load the configuration for login sessions of any shell
if [[ -f "$HOME/.profile" ]]; then
source "$HOME/.profile"
else
echo >&2 "$HOME/.bash_profile: $HOME/.profile not found"
fi
# Load the configuration for interactive non-login Bash sessions
case "$-" in *i*)
if [[ -f "$HOME/.bashrc" ]]; then
source "$HOME/.bashrc"
else
echo >&2 "$HOME/.bash_profile: $HOME/.bashrc not found"
fi;;
esac
我没有这样做export
PATH
,因为 Gordon Davisson 在我从中复制函数的答案中解释说“PATH
应该已经标记为已导出,因此不需要重新导出。” 事实上,我仍然不知道,export
但使用case
的版本pathprepend
一切正常。顺便问一下,Git 进程的父进程是什么,它是我使用的 Bash 进程吗git
?
程序
execve(program_path, argv, envp)
从执行它们的系统调用的第三个参数获取其环境。envp
,就像argv
是一个字符串数组,除了按照envp
惯例字符串是var=value
格式的。程序如何处理这些字符串取决于它们自己,但通常它们采用这些
var=value
字符串并将第一个字符串左边的内容解释=
为环境变量的名称,将右边的内容解释为其值。它们通常将该列表存储起来,当它们在同一个进程或子进程中执行其他命令时,它们将同一个列表作为第三个参数传递给相应的
execve()
系统调用。C 库有用于此目的的帮助程序。该存储旁注列表是
environ
那里的变量,并且可以使用putenv()
/setenv()
/函数来添加/修改/删除那里的变量,并且诸如 之类的函数是系统调用的包装器,可将其自动传递为。这个想法是,环境应该是执行过程中自动继承的东西¹。unsetenv()
execlp()
execve()
environ
envp
大多数 shell 将环境变量映射到 shell 变量。
在类似 POSIX 的 shell 中,
envp
名称与 shell 变量兼容的变量将转换为标有export
属性的 shell 变量。并且export
可以使用特殊的内置实用程序将 shell 变量提升为环境变量,以便将其传递给envp
此后执行的每个命令。~/.profile
是会话初始化文件,当大多数 Bourne 类 shell 被调用为登录 shell时(通过在前面login
添加 来实现),它会对其进行解释。csh 类 shell 的等效文件是,另请参阅zsh 的/ 。-
argv[0]
~/.login
~/.zprofile
~/.zlogin
目前,这通常是在登录时读取的
ssh
(ssh host
仅使用rlogin
模式,而不是不登录的模式)或在虚拟终端或 中ssh host 'shell code'
,很少通过在图形登录会话中启动的终端仿真器来读取。rsh
sudo -i
一些图形环境会尝试将用户的登录 shell 作为非交互式登录 shell 调用来启动,该调用会在登录时解释这些会话环境文件,以尝试在那里获取相同的环境变量,但并非全部。有时还会使用其他机制来定义环境变量。
如果在登录时,您的登录 shell 是作为登录 shell 启动的,并且它类似于 Bourne(而不是 zsh),它将解释中的代码
~/.profile
。解释后,
PATH="~/.local/bin${PATH:+":$PATH"}"
它将更新$PATH
shell变量。由于该变量将在传递给该 shell 的 中找到envp
,因此该变量将被标记为 ,export
并且带有其修改值的变量²将包含在envp
传递给此后执行的每个命令(包括 )的 中git
。如果git
执行getenv("PATH")
,它应该会获得该修改后的值。但要做到这一点,
~/.profile
必须由执行的进程祖先中的 shell 来解释git
。¹ 不要与父子关系混淆。子代从其父代继承了所有内容,但执行会清除整个内存,因此您需要环境之类的机制来传递信息。
² 除了 Bourne shell 之外,除非您调用 ,否则修改 shell 变量不会反映在环境变量中
export
。但是您在 Fedora 或任何现代系统中都找不到 Bourne shell。