【问题标题】:Accessing Linux environment variables without assigned value访问没有赋值的 Linux 环境变量
【发布时间】:2021-03-16 07:50:29
【问题描述】:

我通过包装std::getenvsetenvenviron 编写了用于在C++ 中处理环境变量的小型便利函数。除了设置和获取环境变量之外,我还提供了检查当前环境是否包含某个变量的功能。

#include <cstdlib>
#include <unistd.h>

template <typename VAR_TYPE>
void set(const std::string& variableName, VAR_TYPE varValue, bool overwrite = false) {
    if (!setenv(variableName.c_str(), std::string(variableValue).c_str(), overwrite)) {
      if (errno == ENOMEM) {
        throw std::bad_alloc();
      } else if (errno == EINVAL) {
        throw std::invalid_argument("Variable name invalid: "  + variableName);
      } else {
        throw std::runtime_error("Failed to set environment variable " + variableName);
      }
    }
  }

std::string load(const std::string& variableName, const std::string& defaultValue = "") {
    if (const char* envVariable = std::getenv(variableName)) {
      return std::string(envVariable);
    }
    return defaultValue;
  }

bool contains(const std::string& variableName) {
    for (char** currentEnviron = environ; *currentEnviron; currentEnviron++) {
      if (!std::strncmp(variableName.c_str(), *currentEnviron, variableName.length())) {
        return true;
      }
    }
    return false;
  }

但是,by definition,这仅允许访问格式为 NAME=VALUE 的环境变量。

bash 中,我可以执行以下操作:

$> export SOME_VAR
$> export -p | grep SOME_VAR
declare -x SOME_VAR

显然,SOME_VAR 是在某处定义的,即使我没有为其赋值。但是,当我运行 printenv(它使用我在包装器中使用的相同方法)时,SOME_VAR 未列出。我看过/proc/self/environ,但这仅列出了具有赋值的变量。

我的问题是:

  1. 定义为SOME_VAR_WITH_VALUE=42SOME_VAR_WITHOUT_VALUE 的环境变量有什么区别。
  2. 在 C/C++ 中是否有可能访问没有值的环境变量?

【问题讨论】:

  • 您的检查 -z $SOME_VAR 不检查是否设置了 SOME_VAR,但如果 $SOME_VAR 的长度为 0。如果未设置 SOME_VAR 或设置为空字符串,这将返回 true。
  • 天哪,你是对的。我编辑了我的问题

标签: c++ c shell unix environment-variables


【解决方案1】:

Shell 有一个internal and exported environment variables 的概念。

ABC=xyz 这样的shell 命令设置一个内部变量(可以在Bash 中使用set 看到)。

要导出内部变量,可以使用export 命令。

export ABC=xyz 将创建一个内部变量导出它(导出的可以使用env查看)。

export ABC本身并没有定义任何变量,它只是简单的标记ABC被导出,什么时候它被定义了。

试试这个例子:

$ ABC=xyz
$ set | grep ABC
ABC=xyz
$ env | grep ABC

现在有了export

$ export ABC
$ set | grep ABC
$ env | grep ABC
$ ABC=xyz
$ set | grep ABC
ABC=xyz
$ env | grep ABC
ABC=xyz

注意变量是如何在设置的那一刻导出的。所以export ABC纯粹是一个shell特性,它不会修改环境。它没有 API。

要设置具有空值的环境变量,请使用export ABC=""

$ export ABC=""
$ env | grep ABC
ABC=

【讨论】:

  • 感谢您的精彩解释!因此,我最接近拥有“空”变量(例如通过解析declare 的输出而不跳过箍)是使用export ABC=""
【解决方案2】:

先试试这个:

export SOME_VAR
set | grep SOME_VAR

第二行将不返回任何内容。那是因为第一行没有定义SOME_VAR

关于你的两个问题:

  1. export VARIABLE 无效。它不会创建没有值的变量,也不会更改已设置变量的值。
  2. 环境变量总是有一个值,但该值可能是空字符串。如果你尝试访问不存在的变量,你会得到NULL

【讨论】:

  • 当我使用export SOME_VAR 然后运行export -p 时,SOME_VAR 被列为declare -x SOME_VAR。所以看来export这个语句好像有点效果
  • 没错,名字导出了,你是对的——export VAR有效果。但它没有定义VAR 的值。所以VAR 将被导出,但它的值仍然不会被定义。
【解决方案3】:

最终,bash 只是另一个 Linux 程序。所涉及的魔法有限。它可以改变libcenviron 变量,但它也可以有自己的内部变量。如果在/proc/sef/environ 中没有看到SOME_VAR_WITHOUT_VALUE,则可以推断它是某种 bash 内部变量。

请注意,bash 与大多数 Linux 程序一样,可以并行运行多次。环境在进程之间是分开的。因此,即使在 C 中,您也无法直接访问任何 bash 环境变量。当您的进程启动时,您正在利用 bash 将其环境复制到您的环境这一事实。但是env -i your_process 甚至会停止。

【讨论】:

    猜你喜欢
    • 2017-09-23
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    相关资源
    最近更新 更多