如何在Bash中访问含有空格的环境变量?

14
运行env命令会返回"Clear Workspace=true"。我如何在bash中访问它?顺便说一下,它来自Jenkins参数化构建参数名称。${Clear Workspace}似乎不起作用。
另外,Jenkins如何能够创建这个环境变量?在bash中运行Clear Workspace=true显然行不通,因为它试图使用"Workspace=true"作为"Clear"命令的参数。
当然,我可以将作业参数名称设置为Clear_Workspace,但它呈现给用户的表单中就会显示空格。此外,Jenkins的Maven Build插件有几个带有空格的参数名称,所以必须有一种方法来访问它们。

1
我能够通过 env foo\ bar=3 手动设置一个,但还没有找到一种打印它的方法。 - lurker
@mbratch 你错了。仅仅因为命令没有报错并不意味着你能够设置它。试试输入 env;你找到它了吗? - devnull
3
“@devnull... 确定,好的。这里确实没有必要嘲讽。但是当我运行命令时,env会输出一个列表,并且在变量列表底部显示 foo bar=3。所以它似乎起作用了。它的行为确实有点奇怪。” - lurker
@devnull:我同意mbratch的观点。通过使用env "foo bar=3" bash,我能够创建一个带有环境变量“foo bar”的shell。 - Vaughn Cato
5个回答

9
您可以使用env命令模拟此有趣的位。
env Clear\ Workspace=true bash

这将为您提供一个已设置环境变量的shell。

一种有些取巧的方法,适用于bash 4.0之前的版本,以获取环境变量的值是:

declare -p Clear\ Workspace | sed -e "s/^declare -x Clear Workspace=\"//;s/\"$//"

从Bash 4.0版本开始,尝试以此方式提取环境变量将会返回错误并且无法提取。

除此之外,你需要使用本地代码程序或脚本语言来提取它,例如:

ruby -e "puts ENV['Clear Workspace']"

这种方法不太繁琐,而且如果你没有Ruby的话也可以使用。
perl -e 'print "$ENV{\"Clear Workspace\"}\n";'

同样

python -c 'import os; print os.environ["Clear Workspace"]'

这里是本地代码版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv, char **envp) 
{
  char **env;
  char *target;
  int len;
  if (argc != 2) 
  {
    printf("Syntax: %s name\n", argv[0]);
    return 2;
  }
  len = strlen(argv[1]);
  target = calloc(len+2,sizeof(char));
  strncpy(target,argv[1],len+2);
  target[len++] = '=';
  target[len] = '0';
  for (env = envp; *env != 0; env++) 
  {
    char *thisEnv = *env;
    if (strncmp(thisEnv,target,len)==0)
    {
      printf("%s\n",thisEnv+len);
      return 0;
    }
  }
  return 1;
}

1
感谢您详尽的回答。由于它是 Jenkins 构建作业的一部分,我只能使用 bash,因此我可能会采用您的 trick(declare | sed)解决方案。我在考虑是否值得为了避免用户看到下划线而这样做... - Spycho
通常路径上会有Ruby/Perl/Python...你可以测试它们,如果其中一个缺失,则退而求其次使用hack...或者您可以使用HEREDOC创建临时源文件,然后使用gccjavac编译并执行...但我认为测试Ruby/Python/Perl并回退到声明hack将为您提供一个不错的解决方案。 - Stephen Connolly
啊,谢谢Stephen。我不知道在Jenkins的任务中可以使用脚本语言。非常方便。如果还没有安装的话,我会安装Python的。 - Spycho
这个答案已经过时,可能需要更新。最近的bash版本(5.0+?甚至4.0+?)可能修复了一个bug,使用空格获取环境变量不再起作用:env Clear\ Workspace=true bash -c 'declare -p Clear\ Workspace'返回bash: line 1: declare: Clear Workspace: not found - Ionic

1

bash并不是唯一可以操纵环境的语言:

$ perl -e '$ENV{"Clear Workspace"}="true"; system "env"' | grep Clear
Clear Workspace=true

如果您在 shell 中,您总是可以解析 env 的输出(未经测试)。
value=$(env | while IFS="=" read -r var value; do
                  if [[ $var = "Clear Workspace" ]]; then
                      echo "$value"
                      break
                  fi
              done )

我只能使用bash,因为它是Jenkins工作的一部分。解析环境变量听起来很奇怪,但可能是我唯一可用的解决方案。 - Spycho
Bash只是调用其他程序的工具。你可以编写一个Bash脚本来调用Perl/Ruby/Python程序。 - glenn jackman
假设服务器上安装了其中之一,我可以做到这一点。我得要么编写一个脚本并将其放在服务器某处并引用它,要么将其编写在作业的bash字段中让解释器解析它,但这两种方法都不太理想。另外,bash不仅仅是调用其他程序的工具,还可以做很多其他事情。我一直在寻找一个简单的bash解决方案。 - Spycho

0
以下命令将返回环境变量 "Clear Workspace" 的值:
set | grep "Clear Workspace" | awk -F'=' '{print $NF}'

您可以将其分配给另一个变量而不使用空格,并用于您的目的:

export Clear_Workspace=\`set | grep "Clear Workspace" | awk -F'=' '{print $NF}'\`

试一试。


0
Java支持将名称中带有空格的环境变量传递给进程。以下是一个证明它的示例:
给定 /tmp/test
#!/bin/sh
env > /tmp/test.out

和Test.java

import java.util.*;
import java.io.*;

public class Test {
    public static void main(String[] args) throws Exception     {
        ProcessBuilder pb = new ProcessBuilder("/tmp/test");
        Map<String, String> env = pb.environment();
        env.put("a b", "true");
        pb.directory(new File("/tmp"));
        Process p = pb.start();
    }
}

运行

> javac Test.java
> java Test
> grep "a b" /tmp/test.out 
a b=true

Jenkins使用相同的功能来启动进程

如果您想在不使用Python、Ruby等语言的情况下从纯shell中访问它们,我不确定。我还没有能够实现它。

您可能希望将它们转换为无空格的变量,因为这样可以更好地保证可移植性。


谢谢。我怀疑Maven Build插件能够使用它,但我只能使用bash,因为它只是构建作业的一部分,而不是插件。 - Spycho

-1
Jenkins可能创建的是除了"环境变量"之外的某个东西。
环境变量中不能有空格。引用http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html

Shell和IEEE Std 1003.1-2001的Utilities卷中的实用程序使用的环境变量名称仅由大写字母,数字和下划线('_')组成,其中字符定义在Portable Character Set中,并且不以数字开头。


5
我认为@mbratch已经证明了你可以在环境变量名中使用空格(请参阅问题评论)。仅因为“Shell和Utilities卷中的实用程序使用的环境变量名称仅包含大写字母、数字和下划线”,这并不意味着所有环境变量都必须完全由这些字符组成。 - Spycho

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