如何在bash中将全局变量导出到子进程

如何在bash中将全局变量导出到子进程

我正在使用 Arch 和 bash 以及 Openbox 窗口管理器。
一切都是最新的。
Openbox 配置了一个名为rc.xml

在内部,rc.xml我通常调用bash -c 'command1; command2; etc'
将必要的有用命令序列连接到热键。

我有一个热键定义rc.xml如下

<keybind key="1"><action name="Execute"><command>bash -c '
command1;
command2;
etc;
yad --timeout=1 --text="$pos_x x $pos_y";
'</command></action></keybind>

这一切都按预期工作并且功能齐全,除了全局定义的变量$pos_x并且$pos_y不显示之外。

其中.bashrc定义为

export pos_x=1000  
export pos_y=500  

当我打开一个新的 bash shell 终端窗口并键入时,
echo "$pos_x x $pos_y"
我看到了预期的
1000 x 500

但是,当我在这个新的终端窗口中键入时, bash -c 'echo "$pos_x x $pos_y"'
我什么也看不到,因为显然子进程不会继承全局变量。

如果我输入, bash -c 'source ~/.bashrc; echo "$pos_x x $pos_y"'
我什么也看不到,所以在子进程中获取 .bashrc 没有帮助。

如何将定义的全局变量传递.bashrc给子进程?

我环顾四周,却找不到任何答案。

答案1

Arch 上的默认设置~/.bashrc在文件顶部包含以下行:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

这使得任何非交互式 shell 停止读取该行的文件。由于bash -c启动非交互式 shell,因此~/.bashrc不会完整读取该文件,这就是未定义变量的原因。

所以,你可以尝试:

  1. 将变量放入~/.profile而不是~/.bashrc.无论如何,这是全局变量的自然位置。只要您的登录管理器读取/.profile,这应该有效。

  2. 使用不同的文件。无需将变量定义放入其中~/.bashrc,只需将它们放入~/foo然后发出命令即可bash -c '. ~/foo; echo "$pos_x x $pos_y"

  3. 将变量定义放在我在开头显示的停止读取的行上方~/.bashrc

答案2

来自GNU Bash 手册,6.2 Bash 启动文件:

当 Bash 作为交互式登录 shell 被调用时,或者作为带有 --login 选项的非交互式 shell,它首先从文件中读取并执行命令/etc/profile(如果该文件存在)。读取该文件后,它会按顺序查找~/.bash_profile~/.bash_login、 和~/.profile,并读取并执行命令 第一个存在并且可读。 ...

当 Bash 以非交互方式启动时,例如,要运行 shell 脚本,它会在环境中查找变量 BASH_ENV,如果它出现在其中,则扩展其值,并使用扩展后的值作为要读取和执行的文件的名称。

因此,要正确设置环境,无论 Bash 是以交互方式还是非交互方式启动,仅拥有 是不够的~/.bash_env,您还必须设置变量BASH_ENV并指向它,并在交互模式下显式获取它。

我会将特定于 Bash 的内容放在特定于 Bash 的文件中,并保留~/.profile在其他 shell 中仍然有效的常规设置(如果您有一天决定更改登录 shell)。

首先,创建一个~/.bash_profile包含以下内容的文件:

 [ -f "$HOME/.profile" ] && source "$HOME/.profile"

 if [ -z "$POSIXLY_CORRECT" ]; then
     [ -z "$BASH_ENV" ] && export BASH_ENV="$HOME/.bash_env"
     source "$BASH_ENV"
 fi

"$HOME/.bash_env"然后创建一个包含所有 Bash 特定变量和函数的文件。

顺序很重要:将 source 行放在~/.profile顶部~/.bash_profile使您能够在运行 Bash 时覆盖其中定义的变量。

我还没有检查变量引用的文件是否BASH_ENV是由远程 shell 守护程序(通常rshd)或安全 shell 守护程序调用时获取的sshd。再次引用 Bash 手册,

如果 Bash 确定它正在以这种方式非交互地运行,那么它会从 读取并执行命令~/.bashrc(如果该文件存在并且可读)。

创建包含~/.bashrc以下内容的 可能是个好主意:

 if [ -z "$POSIXLY_CORRECT" ]; then
     [ -z "$BASH_ENV" ] && export BASH_ENV="$HOME/.bash_env"
     source "$BASH_ENV"
 fi

在这种情况下,您可以简化~/.bash_profile

 [ -f "$HOME/.profile" ] && source "$HOME/.profile"
 [ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc"

最后,您希望有一些保护措施,防止您的 中出现多重包含~/.bash_env

[ -n "$BASH_ENV_VERSION" ] && return 0
BASH_ENV_VERSION=.....

...

export注意:对变量(或整个文件中的任何变量)进行 ing是没有意义的,因为~/.bash_env需要获取脚本才能使函数定义在当前 shell 中可访问。出于同样的原因,我们创建的所有文件都不需要 shebang 行。

我们处理了交互式登录 shell 和非交互式 shell。细心的读者可能会反对,认为缺少的部分是交互式非登录 shell。幸运的是,上述步骤涵盖了这些内容:

当启动非登录 shell 的交互式 shell 时,Bash 会从 ~/.bashrc 读取并执行命令(如果该文件存在)。

相关内容