在脚本中执行source .bashrc无效

12

我正在编写一个脚本,用于安装ROS,并在安装完成后使用catkin_make编译工作空间。

我找到了解决问题的方法,但无法解释原因。我有一个名为install.bash的文件,它调用其他文件:

#!/bin/bash

source 01_install_ros.bash

重要的是在01_install_ros.bash文件中:
# variable not set because it is done in the script setup.bash of ros
echo "before source in 01_install_ros"
echo "ROS_ROOT: "$ROS_ROOT
whereis catkin_make
echo ""

echo "source /opt/ros/kinetic/setup.bash" >> $HOME/.bashrc
# doesn't set the variables
source "$HOME"/.bashrc
# the solutions
source /opt/ros/kinetic/setup.bash

# variables not set if I use the source of .bashrc
echo "after source in 01_install_ros"
echo "ROS_ROOT: "$ROS_ROOT
whereis catkin_make
echo ""

如评论中所述,使用源 .bashrc 而不是直接设置 setup.bash 不起作用。我真的不明白为什么。你能解释一下吗?


.bashrc旨在被Bash本身读取。您认为在脚本中执行此操作是否有必要? - ceving
因为我在 01_install_ros.bash 的末尾添加了一行代码,它会从ROS中引用setup.bash文件。所以我需要进行引用。 - onda47
1
使用 exec bash 启动一个新的 Bash,该 Bash 已经读取了更新后的 .bashrc - ceving
我认为你没有理解。我不是在寻找解决方案,而是想要一个解释。为什么使用“source ~/.bashrc”无法正常工作?我知道如何解决它:直接使用“source /opt/ros/kinetic/setup.bash”。 - onda47
创建一个 MCVE 或使用 set -x 自行查找。 - ceving
显示剩余3条评论
1个回答

20
一些平台带有一个名为~/.bashrc的文件,该文件顶部有一个条件语句,如果发现shell是非交互式的,则明确停止处理 - 即使在任何情况下bash只会自动在交互式(非登录)会话中调用~/.bashrc

例如,在Ubuntu 18.04上:

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

同一平台上位于/etc/bash.bashrc中的类似测试:

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

如果是这种情况,从脚本中调用~/.bashrc将没有效果,因为默认情况下脚本在非交互式shell中运行。您的选择是:
  • 要么:在~/.bashrc取消条件语句

  • 要么:在调用source ~/.bashrc之前模拟一个交互式 shell
    需要特定的模拟取决于条件语句的具体情况,但有两种可能的方法;如果您事先不知道遇到哪个条件语句,则可能需要同时使用它们:

    • set -i临时设置为使$-包含i,表示交互式 shell。
    • 如果您知道执行交互性测试的行的内容,请使用grep将其过滤出~/.bashrc,然后使用eval源码的结果(后者通常应避免,但在这种情况下有效地提供与源码相同的功能)。
      请注意,仅确保环境变量PS1具有值是不够的,因为Bash在非交互式 shell 中会主动重置它,有关详细信息,请参见this answer
      • eval "$(grep -vFx '[ -z "$PS1" ] && return' ~/.bashrc)"

或者,如果您控制自己的脚本如何被调用,您可以使用
bash -i script 调用它。


2
“set -i” 似乎无法工作,我也无法手动修改“$-”。 - nupanick
停用条件是否有任何缺点? - deanresin
1
@deanresin:我不这么认为,因为bash只在交互式(非登录)会话中自动引用~/.bashrc - mklement0
@nupanick,答案指出只有在 ~/.bashrc 文件包含首先在答案中列出的条件时,“set -i” 才能起作用,该条件检查(只读)变量 $_。如果条件是基于 $PS1 或类似的内容,则必须使用基于 grep 的技术。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接