无法从Shell脚本成功获取.bashrc


51

通常我们可以~/.bashrc使用此命令来获取文件

source ~/.bashrc

但是,如果我在shell脚本中编写并执行它,则什么也不会发生。为什么?
有什么办法吗?

我的剧本:

#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc

也尝试使用.(dot)代替source。结果相同。

Answers:


26

Shell脚本在其自己的Shell实例中运行。所有变量设置,函数定义等仅影响此实例(可能还包括其子级),而不影响调用外壳程序,因此在脚本完成后它们将消失。

相比之下,该source命令不会启动新的Shell实例,而是使用当前的Shell,因此更改仍然保留。

如果您想使用快捷方式读取.bashrc,请使用Shell函数或别名而不是Shell脚本,例如

alias brc='source ~/.bashrc'

感谢您的快速回复。您的解决方案可能有效,但我必须手动编辑bashrc文件以保存行'aliac brc = ....'。我正在尝试开发一个GUI来更改环境变量。所以我不能手动编辑另一台计算机的bashrc文件。
shantanu 2011年

1
您必须source ~/.bashrc在要更改其环境的Shell中运行。您不能从其他进程更改它。也许(全局)添加此别名可能是GUI安装过程的一部分。
Florian Diesch 2011年

1
所以我是否应该将别名命令放在脚本的前面,然后在我想获取.bashrc的源代码时调用brc或需要将该别名命令放在文件中的某个位置?
user137717

我最终要做的是对Florian Diesch的回答的扩展。您可以只使用多行别名:alias brc ='chmod a + x〜/ .bashrc; 来源〜/ .bashrc'我还很新,所以我不确定这是否被认为是“不良做法”。它确实可以工作。
A_user_appears '18

13

您的.bashrc通常开始时间:

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

由于您的脚本未设置PS1(因为它不是交互式的),因此不会重置路径,因为它会提前退出。为了演示,请修改您的脚本:

    #!/bin/bash
    chmod a+x ~/.bashrc
    PS1='$ '
    source ~/.bashrc

现在,这将使您的脚本可以与新的一起使用.bashrc。注意:脚本退出后,环境将设置为启动脚本之前的状态。更改将在下次启动终端时反映出来。


至少从16.04起(可能在此之前),默认的Ubuntu .bashrc使用更可靠的方法来检查shell是否是交互式的。/etc/bash.bashrc仍然有PS1测试。
赞纳'18

12

尝试:

exec bash

这应该重新加载〜/ .bashrc,〜/ .bash_aliases等。


9
这将用新的bash进程代替当前的bash进程。它并没有比使用它短或容易得多,source但是会破坏任何变量,从而使用户手动设置了-这可能是您想要的,也可能不是。
Florian Diesch 2011年

继续,在执行bashrc采购后在Shell脚本中加上其他命令的情况下,您是否将需要新bash状态的命令放在那之后exec bash,按照我的理解,以后的命令仍将与以前相同的bash设置?

11

我想补充一下拉维的答案

此行为特定于Ubuntu(并且可能是大多数派生的发行版),因为默认~/.bashrc文件以短路(例如Ubuntu 18.04)开头,例如:

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

如果该文件在非交互式shell中运行,则将停止对该文件的评估(您的脚本就是这种情况),因为所有脚本均在非交互式shell中运行,并且随后每个文件都source将继承此属性。

eval 骇客

我发现一个丑陋的黑客可以专门解决Ubuntu问题,eval而不是使用source

eval "$(cat ~/.bashrc | tail -n +10)"

它只是跳过了前几行并评估了其余的行,~/.bashrc因此其余的行将被评估并修改当前执行。

请注意,这是一个神奇的数字,可能不适用于Ubuntu版本。但是如果您正在为或多或少的已知系统编写脚本,则可能是一个很好的解决方案。

更好的解决方案可能涉及使用正则表达式来定位停止评估的特定位。

舍邦替代

在某些情况下可能更好用的另一种替代方法是通过在shebang中添加一个标志来强制脚本在交互式shell中运行:

#!/bin/bash -i

请注意以下几点:


2

没有其他方法对我source /path/to/file有用[ vs . ./path/to/file,alias等...],直到通过本教程,我发现使用了:

#!/usr/bin/env bash 社bang

而不是简单的方法,而是将#!/usr/bin/env参数传递给解释器,我认为这是关键所在– 有关更多信息,请参阅此文档

无论如何,如果任何形式的源命令都不适合您,请尝试检查您的shebang,这可能是问题所在:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.