检查 PS1 是否已设置的目的是什么?

检查 PS1 是否已设置的目的是什么?

[ -n "$PS1" ]in 的目的是什么[ -n "$PS1" ] && source ~/.bash_profile;?该行包含在.bashrc点文件中回购协议

答案1

这是检查 shell 是否是交互式的。在这种情况下,只有~/.bash_profile在 shell 是交互式的情况下才获取文件。

“这是 Shell Interactive 吗?”在 bash 手册中,引用了特定的习惯用法。 (还建议通过测试$-特殊变量是否包含该字符来检查 shell 是否是交互式的i,这是解决此问题的更好方法。)

答案2

这是做什么的

这是测试 shell 是否交互式的一种广泛使用的方法。请注意,它仅适用于 bash,不适用于其他 shell。所以对于 来说是可以的(如果愚蠢的话).bashrc,但是对于 来说它不起作用.profile(由 sh 读取,bash 只是 sh 的可能实现之一,而不是最常见的实现)。

为什么它有效(仅在 bash 中!)

交互式 shell 设置外壳变量PS1到默认的提示字符串。因此,如果 shell 是交互式的,PS1则设置(除非用户.bashrc已将其删除,这在 的顶部还不可能发生.bashrc,并且您可以认为这是一件愚蠢的事情)。

bash 中的情况正好相反:bash 的非交互式实例PS1在启动时会被取消设置。请注意,此行为特定于 bash,并且可以说是一个错误(为什么当isbash -c '… do stuff with $var…'时不起作用?)。但是 bash 的所有版本(包括 4.4)(我写的最新版本)都是这样做的。varPS1

许多系统都会导出PS1到环境中。这是一个坏主意,因为许多不同的 shell 使用PS1不同的语法(例如bash 的提示转义完全不同于zsh 的提示转义)。但它的应用非常广泛,以至于在实践中,看到它PS1已设置并不能可靠地表明 shell 是交互式的。 shell 可能是PS1从环境继承的。

为什么它在这里被(错误)使用

.bashrc是 bash 在交互时启动时读取的文件。一个不太为人所知的事实是,bash 还读取.bashrcis 一个登录 shell,并且 bash 的启发式结论是这是一个远程会话(bash 检查其父级是否是rshdsshd)。在第二种情况下,不太可能PS1在环境中设置,因为还没有运行点文件。

然而,代码使用此信息的方式会适得其反。

  • 如果 shell 是交互式 shell,则它.bash_profile在该 shell 中运行。但.bash_profile它是一个登录时脚本。它可能会运行一些原本每个会话仅运行一次的程序。它可能会覆盖用户在运行该 shell 之前故意设置为不同值的某些环境变量。.bash_profile在非登录 shell 中运行会造成破坏。
  • 如果 shell 是非交互式远程登录 shell,则不会加载.bash_profile.但在这种情况下,加载.bash_profile可能会很有用,因为非交互式登录 shell 不会自动加载/etc/profile~/.profile

我认为人们这样做的原因是针对通过 GUI 登录的用户(一种非常常见的情况)并将环境变量设置放入.bash_profile而不是.profile.大多数 GUI 登录机制会调用.profile但不会调用.bash_profile(读取时.bash_profile需要运行 bash 作为会话启动的一部分,而不是 sh)。通过此配置,当用户打开终端时,他们将获得环境变量。然而,用户将无法在 GUI 应用程序中获取其环境变量,这是一个非常常见的混乱来源。这里的解决方案是使用.profile而不是.bash_profile设置环境变量。在.bashrc和之间添加桥梁.bash_profile会产生比它解决的问题更多的问题。

该怎么办

有一种简单、可移植的方法来测试当前 shell 是否是交互式的:测试该选项是否-i已启用。

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This shell is not interactive";;
esac

.bashrc对于.profile仅当 shell 非交互式时才读取——即与代码的作用相反!.profile如果 bash 是(非交互式)登录 shell,则读取它;如果它是交互式 shell,则不要读取它。

if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi

答案3

看来这个奇怪的概念是由于它bash不是作为 POSIX shell 克隆而是作为Bourne Shell克隆开始的。

因此,POSIX 交互行为($ENV交互 shell 被调用)是后来添加的,bash但并不广为人知。

有一种 shell 可以实现类似的行为。这是cshcsh 授予$prompt的特定值:

$prompt not set          non-interactive shell, test $?prompt.
$prompt set but == ""    .cshrc called by the which(1) command.
$prompt set and != ""    normal interactive shell.

但这既不适用于 Bourne Shell,也不适用于 POSIX shell。

对于 POSIX shell,唯一授予的方法是将交互式 shell 的代码放入文件中:

$ENV

具有 shell 特定名称。它是例如

$HOME/.kshrc    for the korn shell
$HOME/.bashrc   for bash
$HOME/.mkshrc   for mksh
$HOME/.shrc     for the POSIX Bourne Shell

其他人提到了 shell 标志-i,但这不适用于可靠的编程。 POSIX 既不要求它set -i有效,也不$-包含i交互式 shell。 POSIX 仅要求sh -i强制 shell 进入交互模式。

由于变量$PS1可以从环境中导入,因此即使在非交互模式下它也可能具有值。事实上,任何非交互式 shell 中的bash unsetsPS1都不是由标准授予的,也不是由任何其他 shell 执行的。

因此,干净的编程(即使使用bash)是将交互式 shell 的命令放入$HOME/.bashrc.

答案4

我首先要谈谈 Debian 以及大多数情况下 Ubuntu 为 bash 设置的内容。后者涉及其他系统。

在shell启动文件的设置上有很多意见。
我也有我的意见,但我会尝试展示正确设置的现有示例。
我将使用 debuan,因为很容易找到其文件的示例。
而且debian被大量使用,所以设置都经过了很好的测试,

检查 PS1 是否已设置的目的是什么?

只是为了查明 shell 是否是交互式的。

默认/etc/profiledebian 中的和 ubuntu(来自 /usr/share/base-files/profile):

if [ "${PS1-}" ]; then
    if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then

if 的读法是:如果是交互式的(PS1 默认设置)并且它是一个 bash shell(但不充当默认外壳sh),则将 PS1 更改为特定的新外壳(不是默认外壳)。

默认/etc/bash.bashrcdebian 中的还包含:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

它的作用非常清楚:如果交互式不来源(其余)。

然而,/etc/skel/.bashrc一个例子测试交互式 shell 的正确方法(使用$-):

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

这应该清楚地表明了 PS1 的原因和一种替代方案。

正确的顺序

应避免您报告的设置。
顺序(从系统设置到更具体的用户设置(对于 bash))是/etc/profile/etc/bash.bashrc~/.profile最后是~/.bashrc。这将最广泛的影响(以及更多 shell)放在/etc/profile(由 root 拥有)中,其次是/etc/bash.bashrc(也由 root 拥有),但只影响 bash。然后是 中的个人设置$HOME,第一个~/.profile适用于大多数 shell ~/.bashrc(几乎相当于~/.bash_profile),仅特定于 bash。

~/.bashrc因此,来源是错误的~/.profile,它将 bash 的特定用户设置转换为更通用的设置,即影响更多炮弹。除非如果这样做:

# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

它检查 bash 是否正在运行,并且仅.bashrc在运行时才加载。

这是来自 Debian 的上游决定。其原理解释如下

事实上,相反,(或)~/.profile中的采购只是重新应用应该已经加载到特定用例的一般规则,因此“还不错”(我不是说“好”)。我并不是说好,因为这可能会导致文件来源循环。就像子目录加载父目录一样,这是一个目录循环。~/.bash_profile~/.bashrc

在这种交叉源中,检查交互式 shell 才有意义。仅当 shell 是交互式的时才会~/.bashrc加载,但它反过来可能会加载~/.profile(或相反),并且在这种情况下,可以使用检查交互式 shell。

相关内容