---
title: "【Jenkins】用户与环境变量问题"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/jenkins-user-env-variable-issues/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/03-软件工程与质量保障/CI-CD与质量保障/CI-CD工具链/【Jenkins】用户与环境变量问题.md"
content_hash: 5d446690418788d5e03b37311b83284789137d22be62cfa31fd5e944130c0905
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# 【Jenkins】用户与环境变量问题

﻿# 【Jenkins】用户与环境变量问题

> 创建时间：2021/7/6 16:08

* 综述
  * Jenkins运行Shell的机制
    * SSH远程登录与环境变量
    * 运行shell脚本
    * 修改What shell is used
  * Jenkins不同层次环境变量的加载特性和时机
    * 全局配置、节点配置和节点本身环境变量之间的关系
    * 节点本身环境变量加载方式
      * Master Windows
      * Master Linux
      * Slave Windows
      * Slave MacOS
    * Pipeline中通过environment字段
  * Jenkins环境变量设置方式
    * 全局变量
    * 节点本身的环境变量
      * 在Jenkins中设置全局变量
      * 使用Initialization files
    * 某个Project的环境变量
      * Pipeline脚本中使用
      * shell脚本中设置
    * 某个Shell进程（会话）的环境变量
  * 内置环境变量

## 综述

Jenkins下自动运行shell/bat与手动运行、在命令行/终端下运行的区别主要在于两点：

  * 登陆的用户身份不同，导致权限不同
  * 加载的环境变量不同，导致一些命令无法找到，或者运行结果出错

## Jenkins运行Shell的机制

### SSH远程登录与环境变量

Jenkins使用SSH远程登录Unix系统时，实质上是直接在SSH登录的命令中加入了指令，属于non-interactive + non-login shell，类似于以下语句：

```csharp
string a = &quot;test&quot;;
string tmp = &quot;est&quot;;
string b = &quot;t&quot; + tmp;
Console.WriteLine(string .ReferenceEquals(str1, str2));

```

因此， **不会读取任何文件** （profile等）
因此，Jenkins远程执行任务，使用的环境变量只能使用Jenkins来配置，用户在profile等文件中配置的变量是无效的。有两种思路：

  * 直接设置环境变量。
  * 使用source指令，使profile或rc文件生效。

### 运行shell脚本

Jenkins运行Shell命令的机制与以下代码类似，每执行一段sh命令，shell都会启动一个sh程序，传入参数来执行。

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-001-2af138a09e6a.png](/media/a8d8c55046521eccbbb5.png)

```csharp
string a = &quot;test&quot;;
string tmp = &quot;est&quot;;
string b = &quot;t&quot; + tmp;
Console.WriteLine(string .ReferenceEquals(str1, str2));

```

### 修改What shell is used

方法一：Manage Jenkins --> Configure System --> Shell executable

> （不推荐）因为这会修改在所有节点上运行shell的路径，如果windows和linux系统混用，会导致出错。

方法二：declare your shell on the first line of your script as you do in any shell script file:

```csharp
string a = &quot;test&quot;;
string tmp = &quot;est&quot;;
string b = &quot;t&quot; + tmp;
Console.WriteLine(string .ReferenceEquals(str1, str2));

```

## Jenkins不同层次环境变量的加载特性和时机

### 全局配置、节点配置和节点本身环境变量之间的关系

  * 全局配置：Config System当中设置Global properties -> Environment variables
  * 节点配置：可以在某个节点设置Configure -> Environment variables
  * 节点本身：Jenkins启动某个节点时，会加载这个节点上的环境变量。

全局配置和节点配置都可以引用节点本身的环境变量。节点本身的环境变量在初始化时就会加载好，而配置当中环境变量的设定在此之后。
全局配置和节点配置的环境变量，如果名称不同，并且在不出现循环引用的情况下，可以互相引用。
如果名称相同，优先使用节点的配置，全局的配置不生效。节点配置中的环境变量所引用的环境变量来自全局配置，还是来及节点本身，笔者暂时没有确定，两种情况似乎都会出现。

总之，Jenkins中对全局、节点配置的环境变量都可以引用节点本身的环境变量，全局和节点的配置也可以相互引用，但是初始化顺序不明确，如果出现循环引用，会产生多次递归现象。

### 节点本身环境变量加载方式

#### Master Windows

Jenkins以服务的形式安装运行，系统变量会加载，用户变量不会被加载。修改了环境变量后，需要重启Jenkins才能加载到。

#### Master Linux

以用户jenkins的身份登录，大多数环境变量都是与Jenkins自身有关的，基本不会加载什么用户配置文件里的环境变量。

#### Slave Windows

在Windows节点上环境变量会加载的比较全。系统变量和用户变量都会被加载到。
双击运行或者cmd运行，就是以当前登录的用户身份运行的，系统变量和用户变量都会被加载到。
如果命令行运行，那么在命令行设置过的环境变量会被继承。

#### Slave MacOS

**不会读取任何环境变量配置文件** 。可以在Prefix Start Agent Command中进行设置。

### Pipeline中通过environment字段

通过Enviroment字段的方式设置的环境变量，不能引用已有的环境变量。
设置代码如下：

```csharp
string a = &quot;test&quot;;
string tmp = &quot;est&quot;;
string b = &quot;t&quot; + tmp;
Console.WriteLine(string .ReferenceEquals(str1, str2));

```

打印结果：

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-006-e9df4973a88e.png](/media/79fa75a4384279d2f44f.png)

## Jenkins环境变量设置方式

  * 全局环境变量（所有节点，所有Job都生效的）
  * 某个节点（node）的环境变量
  * 某个项目（project）的环境变量
  * 某次构建（build）的环境变量

### 全局变量

Manage Jenkins -> Global properties -> Environment variables -> Add

### 节点本身的环境变量

node上执行的的所有 shell 命令都会继承这个node的环境变量。

#### 在Jenkins中设置全局变量

Manage node -> Configure -> Environment variables -> List of variables -> Add

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-002-a29fc8a59bf2.png](/media/9a1bb31c84b9873ddab8.png)

这个环境变量在构建(Build)执行时候才生效。

#### 使用Initialization files

如果 Launch agents via SSH，可以在节点的配置中添加命令来加载profile文件：
Configure -> Launch method -> Launch Launch agents via SSH -> Prefix Start Agent Command

> 注意：每条语句都要使用分号结尾

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-003-63fd855a5ab5.png](/media/8fafa7076e6a692d019f.png)

Jenkins会在启动代理进程时，将上述命令加入到shell语句当中

```csharp
string a = &quot;test&quot;;
string tmp = &quot;est&quot;;
string b = &quot;t&quot; + tmp;
Console.WriteLine(string .ReferenceEquals(str1, str2));

```

环境变量会加到这个Node的Environment Variable列表中：

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-004-5d201cbc834b.png](/media/10fadb08c69293a69644.png)

### 某个Project的环境变量

#### Pipeline脚本中使用

可以在各个级别上设置环境变量

![assets/0028 - 【Jenkins】用户与环境变量问题__resource-005-ceb5c8dfbadf.png](/media/ca4624e4b2d57290037d.png)

#### shell脚本中设置

可以通过-i参数和-l参数让bash为login shell and interactive shell，就可以读取/etc/profile和~/.bash_profile等文件。

即在jenkins Execute Shell里可以这么写

```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```

### 某个Shell进程（会话）的环境变量

  * 可以使用export命令设置
  * 可以使用Initialization files - 在shell命令前添加描述

```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```

## 内置环境变量

```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```
```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```
