Linux下的环境变量到底有什么限制?

前言

最近在排查一个eureka问题,发现客户设置了环境变量eureka.client.serviceUrl.defaultZone
于是在本地尝试复现这个现场,发现我设置不了这个环境变量,提示:

1
2
# export eureka.client.serviceUrl.defaultZone=http://localhost:8761/
sh: export: eureka.client.serviceUrl.defaultZone: bad variable name

但是在k8s中,可以给pod设置带点的环境变量。

于是看了下Linux中环境变量的限制。

首先看一下为什么export会报错

以busybox为例,export是一个内置命令,所以执行这个命令的时候,直接调用了 exportcmd 函数

这个函数的核心逻辑就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 函数setvar
static struct var *
setvar(const char *name, const char *val, int flags)
{
//……
q = endofname(name);
p = strchrnul(q, '=');
namelen = p - name;
if (!namelen || p != q)
ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
//……
}

// endofname.c
#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))

const char* FAST_FUNC
endofname(const char *name)
{
if (!is_name(*name))
return name;
while (*++name) {
if (!is_in_name(*name))
break;
}
return name;
}

仔细观察endofname的逻辑就会发现,shell对于环境变量名字的限制是:

  • 只能以字母开头
  • 只能包含字母和数字

这样一看,eureka.client.serviceUrl.defaultZone这个环境变量名不符合上述要求的,所以报错。

但是为什么k8s可以设置这个环境变量成功呢?

以为k8s调用的是系统调用 setenv

setenv对name的要求很简单,不为NULL,不是空字符串就可以。所以k8s可以设置带点的环境变量。

env命令同样使用的是setenv系统调用,我们用env命令试一试:

1
2
3
4
5
6
# env -i "a.b.c=123" "a b c=123" " =123" sh -c "env"
SHLVL=1
a.b.c=123
PWD=/app
=123
a b c=123

可以发现,名字是空格、包含空格、包含点的环境变量,都可以设置成功。

总结

内核对环境变量没有做太多限制,但是shell为了防止出错,做了一些限制。

作为开发者,为了方便最终用户使用,还是尽可能遵守shell的环境变量限制比较好。

Linux下的环境变量到底有什么限制?

https://www.robberphex.com/envvars-limitation/

作者

Robert Lu

发布于

2021-04-01

许可协议

评论