Answers:
这是在检查外壳是否是交互式的。在这种情况下,仅~/.bash_profile
在外壳是交互式的情况下才采购文件。
请参阅“此Shell是否具有交互性?” 在bash手册中,引用了该特定用法。(它还建议通过测试$-
特殊变量是否包含i
字符来检查外壳是否是交互式的,这是解决此问题的更好方法。)
bash
当非交互式(您之前的注释中的键入)是IMO错误时,这会取消PS1的设置,而PS1并不是bash特定的变量,因此无需进行任何设置。它是唯一执行此操作的外壳程序(尽管即使是非交互式的,它yash
也会设置PS1
为默认值)。
[[ $- = *i* ]] && source ~/.bash_profile
。
[ -n "${PS1}" ]
,但是我仍然更新了答案,以强调bash手册还建议/建议检查$-
以确定shell是否是交互式的,希望您能改善答案。干杯!
这是测试外壳是否是交互式的一种广泛的方法。注意,它只能在bash中工作,而不能与其他shell一起工作。因此,对于来说还可以(如果很愚蠢).bashrc
,但不能在.profile
其中使用(由sh读取,bash只是sh可能的实现之一,而不是最常见的实现)。
交互式外壳将shell变量PS1
设置为默认提示字符串。因此,如果外壳是交互式的,PS1
则进行设置(除非用户.bashrc
已将其删除,但在顶部尚未发生这种情况.bashrc
,您仍然可以认为这是一件很愚蠢的事情)。
相反,在bash中是正确的:bash的非交互式实例PS1
在启动时未设置。请注意,此行为特定于bash,并且可以说是一个bug(为什么bash -c '… do stuff with $var…'
当var
is 时不起作用PS1
)。但是所有bash版本(包括4.4以下)(我写的是最新版本)都可以做到这一点。
许多系统都输出PS1
到环境中。这是一个坏主意,因为有许多不同的shell使用,PS1
但语法不同(例如bash的提示转义与zsh的提示转义完全不同)。但是它已经足够广泛了,以至于在实践中,看到它PS1
已经设置并不能可靠地表明Shell是交互式的。该外壳可能是PS1
从环境继承的。
.bashrc
是bash在交互时在启动时读取的文件。一个不太为人所知的事实是,bash还会读取.bashrc
登录外壳程序,并且bash的启发式方法得出的结论是这是一个远程会话(bash检查其父对象是rshd
还是sshd
)。在第二种情况下,不太可能PS1
在环境中进行设置,因为尚未运行任何点文件。
但是,代码使用此信息的方式适得其反。
.bash_profile
它将在该外壳中运行。但是.bash_profile
是登录时脚本。它可能会运行某些旨在每个会话仅运行一次的程序。它可能会覆盖用户在运行该Shell之前故意将其设置为其他值的一些环境变量。.bash_profile
在非登录外壳中运行会造成破坏。.bash_profile
。但是在这种情况下,加载.bash_profile
可能会很有用,因为非交互式登录外壳不会自动加载/etc/profile
和~/.profile
。我认为人们这样做的原因是因为用户通过GUI登录(这是很常见的情况),并且将环境变量设置置于.bash_profile
而不是中.profile
。大多数GUI登录机制都调用.profile
但不调用.bash_profile
(读取.bash_profile
需要在会话启动过程中运行bash,而不是sh)。使用此配置,当用户打开终端时,他们将获得其环境变量。但是,用户不会在GUI应用程序中获得其环境变量,这是造成混乱的非常常见的原因。解决方案是使用.profile
而不是.bash_profile
设置环境变量。在两者之间架起一座桥梁.bashrc
,.bash_profile
带来的问题比解决的问题多。
有一种简单,可移植的方法来测试当前外壳是否是交互式的:测试是否-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
[[ -o interactive ]]
(KSH时,bash,zsh中)或case $- in (*i*) ...; esac
(POSIX)
PS1
如果不以交互方式运行,我的bash(版本4.4.12)实际上似乎未设置。测试起来很容易:PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
不会打印任何内容,而会PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
打印$PS1
bash启动文件中的set 值(它不会打印字符串“ cuckoo”)。
$-
包含i
带有交互式shell的内容。
[ -n "${PS1}" ]
说错是有点过头了,毕竟只有当有人导出PS1时它才会中断(在您的回答中,您说这是个坏主意,甚至进入了原因),但这不会影响无论如何bash(因为如果外壳是非交互的,因为它会设置PS1和PS2,所以它会设置为PS1和PS2。)也许使用诸如“粘性”之类的词或谈论该方法的“局限性”会更好。我不认为这完全是“错误的”。如果有任何问题导出PS1,那是肯定的!无论如何,感谢您对此进行详细介绍。
似乎这个奇怪的概念是由于bash
不是以POSIX shell克隆而是以Bourne Shell
克隆开始的事实造成的。
结果,POSIX交互行为($ENV
被称为交互式shell)已在以后添加到bash
并且并不广为人知。
有一个外壳可以授予类似的行为。这是csh
和$prompt
具有特定值的csh授予:
$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
具有外壳程序特定名称。这是例如
$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
可以从环境中导入变量,因此即使在非交互模式下也可以具有值。bash
unset
s PS1
在任何非交互式外壳中的事实不是由标准授予的,也不由任何其他外壳完成。
所以干净的编程(甚至使用bash
)都是将交互式shell的命令放入$HOME/.bashrc
。
我首先要讲的是Debian,在大多数情况下,Ubuntu也会使用bash。后者涉及其他系统。
在shell启动文件的设置中,有很多意见。
我也有自己的看法,但是我将尝试显示正确设置的现有示例。
我将使用debuan,因为它很容易找到其文件示例。
而且debian被大量使用,因此设置已经过充分测试,
只找出外壳是否是交互式的。
debian和ubuntu中的默认值/etc/profile
(来自/ usr / share / base-files / profile):
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
if的内容为:if交互(PS1默认设置),并且它是一个bash shell(但不用作默认值sh
),然后将PS1更改为特定的新PS1(而不是默认值)。
debian中的默认值/etc/bash.bashrc
还包含:
# 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
。/etc/profile
它将最广泛的效果(对于更多的shell)放在(由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
)只重应用应该已经已经加载到一个特定的使用情况,因此一般规则“并不坏”(我不是说“好”)。我并不是说很好,因为这可能会导致文件源循环。就像子目录加载父目录时一样,这就是目录循环。
在这种交叉采购中,对交互式外壳的检查才有意义。仅当外壳是交互式的时才~/.bashrc
加载,但反过来可能会加载~/.profile
(或反之),在这种情况下,可以使用检查交互式外壳。
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )
,它只是打印出来[]
。这似乎zsh中并不尽相同,至少从实验......在任何情况下,意图的[ -n "$PS1" ]
是检查是否外壳是交互与否。