[ -n "$PS1" ] 在 bashrc 中的用途

sho*_*tes 12 osx bash bashrc

[ -n "$PS1" ]in 的目的是什么[ -n "$PS1" ] && source ~/.bash_profile;?此行包含在.bashrcdotfiles repo的 a 中。

fil*_*den 22

这是检查外壳是否是交互式的。在这种情况下,仅~/.bash_profile当 shell 是交互式的时才获取文件。

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

  • 当非交互式(您之前评论中的错字)是一个错误 IMO 时,`bash` 会取消设置 PS1,PS1 不是特定于 bash 的变量,它没有取消设置的业务。它是唯一能做到这一点的 shell(尽管 `yash` 也会将 `PS1` 设置为默认值,即使是在非交互式的情况下)。 (3认同)

Gil*_*il' 21

这是做什么的

这是测试 shell 是否具有交互性的一种普遍方法。请注意,它仅适用于 bash,不适用于其他 shell。所以它可以(如果很傻) for .bashrc,但它不能在.profile(由 sh 读取,而 bash 只是 sh 的可能实现之一,而不是最常见的实现)。

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

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

在 bash 中反之亦然:bash 的非交互式实例PS1在启动时未设置。请注意,这种行为是具体的抨击,并且可以说是一个bug(为什么会bash -c '… do stuff with $var…'在不工作varPS1?)。但是所有版本的 bash 包括 4.4(我写的最新版本)都这样做。

许多系统导出PS1到环境。这是一个坏主意,因为许多不同的外壳使用PS1但具有不同的语法(例如,bash 的提示转义zsh 的提示转义完全不同)。但它已经足够普遍,以至于在实践中,看到它PS1被设置并不是 shell 是交互式的可靠指标。shell 可能继承PS1自环境。

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

.bashrc是 bash 在交互式启动时读取的文件。一个鲜为人知的事实是 bash 还读取.bashrc是登录 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
Run Code Online (Sandbox Code Playgroud)

这是非常有用的.bashrc,以读取.profile如果shell非交互式只-即的代码做的正好相反!阅读.profile,如果是bash(非交互式)登录shell,如果它是一个交互的shell不读它。

if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
Run Code Online (Sandbox Code Playgroud)

  • 可能值得注意的是,测试 shell 是否具有交互性的更好方法是使用 `[[ -o interactive ]]` (ksh, bash, zsh) 或 `case $- in (*i*) ...; esac`(POSIX) (4认同)
  • 如果不以交互方式运行,我的 bash(版本 4.4.12)实际上似乎会取消设置 `PS1`。测试很容易:`PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'` 不会打印任何内容,而 `PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'` 打印 bash 启动文件中设置的 `$PS1` 的值(它不会打印字符串“布谷鸟”)。 (2认同)