导出变量在终端中有效,但在 shell 脚本中无效

导出变量在终端中有效,但在 shell 脚本中无效

我正在使用 Ubuntu Focus 并尝试启动

VBoxManage list vms

使用不同的配置目录。这可以通过更改(或设置)来实现VBOX_USER_HOME,并且如果我简单地输入:

export VBOX_USER_HOME="/new/config/path"
VBoxManage list vms

但是,当我在 bash 脚本中尝试相同的代码时:

#!/bin/bash
export VBOX_USER_HOME="/new/config/path"
echo "$VBOX_USER_HOME"
env | grep VBOX_USER_HOME
VBoxManage list vms

该变量不会被“看到”,VBoxManage因此它会列出在默认位置配置的虚拟机,即使该变量显然已成功导出到 env。输出如下所示:

/new/config/path
VBOX_USER_HOME=/new/config/path
lists the machines from default config

我知道这/usr/bin/vboxmanage是一个指向最终调用真正应用程序的脚本的链接$INSTALL_DIR/VBoxManage。为了确保 VBox 脚本不会清理环境,我尝试直接调用二进制文件。然而,这没有什么区别。

那么,为什么$INSTALL_DIR/VBoxManage当我从终端导出时导出的变量是可见的,但当我从脚本导出时导出的变量却是不可见的?

修正案: 我刚刚发现这是 Virtual Box 的某种竞争条件问题。如果我在终端中执行导出并$INSTALL_DIR/VBoxManage list vms随后直接运行,它会像脚本一样错误地显示默认配置中的虚拟机。后续调用始终返回旧列表后续调用将在 5 到 10 秒后显示新列表。如果我执行导出并等待一段时间,列表将正确更新到在新位置配置的虚拟机。现在,后续调用始终返回新列表。所以我的问题的解决方案是在脚本中插入睡眠。无论如何,我会奖励能够解释这种意外行为的答案。

答案1

我曾经遇到过完全相同的问题,因为我的机器上有 2 个磁盘 - 一个用于存储数据的小型 SSD 磁盘/(现已升级到 1 TB,因此不再那么小)和一个用于数据的大型 HDD。由于 SSD 磁盘空间不足,我将所有虚拟机保留在巨大的 HDD 上。我发现运行后vboxmanage list vms出现了2个与Virtualbox相关的进程:

$ ps aux | grep -i '[V]irt'
ja       29172  0.0  0.1  36084 11240 ?        S    21:17   0:00 /usr/lib64/virtualbox/VBoxXPCOMIPCD
ja       29178  1.0  0.2 523564 21256 ?        Sl   21:17   0:00 /usr/lib64/virtualbox/VBoxSVC --auto-shutdown

它们在一段时间(大约 20 秒)后终止。这些过程描述于虚拟盒手册:

5.7.6。 VBoxSVC IPC 问题

在 Linux 上,Oracle VM VirtualBox 使用自定义版本的 Mozilla XPCOM(跨平台组件对象模型)进行进程间和进程内通信 (IPC)。进程 VBoxSVC 充当不同 Oracle VM VirtualBox 进程之间的通信中心,并维护全局配置,例如 XML 数据库。启动 Oracle VM VirtualBox 组件时,会自动启动进程 VBoxSVC 和 VBoxXPCOMIPCD。它们只能从运行它们的用户帐户访问。 VBoxSVC 拥有 Oracle VM VirtualBox 配置数据库,该数据库通常驻留在 ~/.config/VirtualBox 或操作系统的相应配置目录中。当它运行时,配置文件被锁定。各个 Oracle VM VirtualBox 组件和 VBoxSVC 之间的通信是通过位于 /tmp/.vbox-username-ipc 中的本地域套接字执行的。如果存在通信问题,例如 Oracle VM VirtualBox 应用程序无法与 VBoxSVC 通信,请终止守护程序并删除本地域套接字目录。

事实上,cat /tmp/.vbox-$(whoami)-ipc/lock显示了进程的 PID VBoxXPCOMIPCD。这就是问题的根本原因。

现在,我还没有发现任何提及这一点的内容,vboxmanage --help所以我认为你不能轻易绕过它。你可能总是想 VBoxXPCOMIPCD在使用之前杀死它vboxmanage,这很容易做到,因为 PID 总是被保存的。

相关内容