为什么从源代码编译时 Bash 的行为有所不同?

为什么从源代码编译时 Bash 的行为有所不同?

我跑了

git clone https://git.savannah.gnu.org/git/bash.git
cd bash/
./configure
make
./bash

我注意到新启动的 Bash 实例没有从父 shell 继承环境,特别是定义 shell 提示符的 PS1 变量。继承适用于/bin/bash

源文件列表/bin/bash和是一样的./bash

./bash  -lixc exit 2>&1 | sed -n 's/^+* \(source\|\.\) //p'
/bin/bash  -lixc exit 2>&1 | sed -n 's/^+* \(source\|\.\) //p'

编辑:正如aviro提到的,PS1是在没有导出的情况下定义的,所以当我尝试导出它时它被继承了,所以我最初的问题是错误的。在我的机器上 PS1 在两个文件中定义 /etc/bash/bashrc

# If not running interactively, don't do anything
[[ $- != *i* ]] && return
[[ $DISPLAY ]] && shopt -s checkwinsize
PS1='[\u@\h \W]\$ '

/etc/bash/bashrc.d/artix.bashrc

if ${use_color} ; then
    if [[ ${EUID} == 0 ]] ; then
        PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
    else
        PS1='\[\033[01;36m\][\u@\h\[\033[01;37m\] \W\[\033[01;36m\]]\$\[\033[00m\] '
    fi
else
    if [[ ${EUID} == 0 ]] ; then
        # show root@ when we don't have colors
        PS1='\u@\h \W \$ '
    else
        PS1='\u@\h \w \$ '
    fi
fi

当我运行./bashPS1时\s-\v\$,我不知道为什么。

列出所有源文件的命令显示,在使用 运行时,这两个文件都应该是源文件./bash,但由于某种原因,它们不是源文件,或者 shell 以不同的类型/模式启动。为什么?

答案1

首先,您需要了解这PS1通常是 外壳变量,这意味着它不会被孩子继承。因此,除非您显式运行export PS1=...并创建PS1环境变量,否则每个新进程都会从 rc 文件而不是父进程bash获取(和其他 shell 变量)。PS1所以你首先需要找出你的确切PS1定义在哪里。

您可以通过导出您的PS1

export PS1

然后运行你的./bash.您将看到,在这种情况下,PS1将由新 shell 继承。


那么为什么你的编译没有从 rc 文件中bash获得你期望的 shell 变量呢?PS1

这是我的猜测:在许多系统上,PS1是在/etc/bash.bashrc.但并非所有bash版本都会读取此文件。这取决于如何bash编译。一个好的经验法则是检查您的bash手册页。例如,对于乌班图你会看到的:

当启动非登录 shell 的交互式 shell 时,bash 会读取并执行以下命令/etc/bash.bashrc~/.bashrc,如果这些文件存在。这可以通过使用该--norc 选项来抑制。 file选项将强制 bash 从 file 而不是和--rcfile读取并执行命令。/etc/bash.bashrc~/.bashrc

然而,/etc/bash.bashrc文中甚至没有提及bash手册页你从那个[git]下载的:

当启动非登录 shell 的交互式 shell 时,bash 会读取并执行来自 的命令(~/.bashrc如果该文件存在)。这可以通过使用该--norc选项来抑制。 file--rcfile选项将强制 bash 从文件而不是 ~/.bashrc.

此外,在README从 Debian的文件bash,你会看到:

5. 什么是/etc/bash.bashrc?似乎没有记录。

Debian 版本的 bash 是用一个特殊选项 ( -DSYS_BASHRC) 编译的,该选项使得先bash读取/etc/bash.bashrc~/.bashrc

因此,在git您使用的存储库中,您将看到 config-top.h定义的行SYS_BASHRC默认被注释掉。

/* System-wide .bashrc file for interactive shells. */
/* #define SYS_BASHRC "/etc/bash.bashrc" */

所以你的bash默认构建不会/etc/bash.bashrc在启动时读取,如果你PS1在那里定义,它也不会得到它。

如果您删除此行的注释:

#define SYS_BASHRC "/etc/bash.bashrc"

再次运行make,我的猜测是您的新内容bash将显示PS1您期望的变量。

相关内容