为什么我无法在节点js中更新env变量

时间:2019-10-17 06:03:18

标签: node.js node-modules

我想更新节点js中的env变量,但是我无法更新其env变量,我尝试使用console.log(process.env.DB_HOST),但仍然获得了旧的价值,在这里我添加了整个代码,可以任何人都请查看它,并帮助我解决此问题,

function exec_api() { 
    return new Promise(async function (resolve) {
        const execSync = require('child_process').exec;
        //let child_process_obj = execSync('DB_HOST='+process.env.UNITTEST_DB_HOST+' DB_DATABASE='+process.env.UNITTEST_DB_DATABASE+'  DB_USERNAME='+process.env.UNITTEST_DB_USERNAME+' DB_PASSWORD='+process.env.UNITTEST_DB_PASSWORD+'  PORT='+process.env.UNITTEST_SERVICE_PORT+' ./node_modules/.bin/nodemon main.js'); 
        await execSync('export DB_HOST=' + process.env.UNITTEST_DB_HOST);
        await execSync('export DB_DATABASE=' + process.env.UNITTEST_DB_DATABASE);
        await execSync('export DB_USERNAME=' + process.env.UNITTEST_DB_USERNAME);
        await execSync('export DB_PASSWORD=' + process.env.UNITTEST_DB_PASSWORD);
        await execSync('export PORT=' + process.env.UNITTEST_API_BACKEND_PORT);
        let child_process_obj = await execSync('node main.js');
        unittest_api_backend_process_id = child_process_obj.pid;
        resolve(true);
    });
}

2 个答案:

答案 0 :(得分:1)

TLDR:只需更改process.env

要更改,添加或删除环境变量,请使用process.env。以下是显示其工作方式的测试代码:

main.js 中:

console.log(process.env.DB_DATABASE);

exec.js 中:

const execSync = require ('child_process').execSync;

process.env.DB_DATABASE = 'foo'; // this is ALL you need to do

console.log(execSync('node main.js').toString('utf8'));

使用上述两个文件,如果运行node exec.js,则会在控制台中看到foo打印出来。这是从main.js打印的,它继承了exec.js的环境。

所以您需要在代码中做的只是:

我想更新节点js中的env变量,但是我无法更新其env变量,我尝试使用console.log(process.env.DB_HOST),但是我仍然获得旧值,在这里我添加了我的整个代码,任何人都可以查看一下,并帮助我解决此问题,

function exec_api() { 
    return new Promise(function (resolve) {
        const exec = require('child_process').exec;

        // The following is node.js equivalent of bash "export":
        process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
        process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
        process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
        process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
        process.env.PORT = process.env.UNITTEST_SERVICE_PORT;

        let child_process_obj = exec('node main.js', {
            stdio: ['inherit', 'inherit', 'inherit']
        });

        unittest_api_backend_process_id = child_process_obj.pid;

        resolve(true);
    });
}

请注意,如果您希望在main.js结束时返回承诺,则需要执行以下操作:

function exec_api() { 
    return new Promise(function (resolve) {
        const exec = require('child_process').exec;

        // The following is node.js equivalent of bash "export":
        process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
        process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
        process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
        process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
        process.env.PORT = process.env.UNITTEST_SERVICE_PORT;

        let child_process_obj = exec('node main.js', {
            stdio: ['inherit', 'inherit', 'inherit']
        });

        unittest_api_backend_process_id = child_process_obj.pid;

        child_process_obj.on('exit', () => resolve(true));

        // ^^^ Cannot use `await` as the API is not promise based
        //     but event based instead.
    });
}

长话短说:export为什么无效的完整解释

在unixen上,环境变量,乃至整个环境(包括当前工作目录,根目录(可通过chroot更改)等)都不是shell的功能。它们是流程的特征。

我们可能熟悉某些Shell的export语法来设置子进程的环境变量,但这就是Shell的语法。它与环境变量本身无关。例如,C / C ++不使用export而是使用setenv()函数来设置环境变量(实际上,内部是bash / sh / ksh等在实现export时所做的事情)。 / p>

在node.js中,用于读取和设置环境变量的机制是通过process.env

为什么要求外壳程序不起作用

这不仅仅是一个node.js问题。在bash中也无法使用:

exporter.sh 中:

#! /bin/bash

export DB_DATABASE=$1

exec.sh 中:

#! /bin/bash

./exporter.sh foo
echo $DB_DATABASE ;# does not print "foo"

这是unixen的核心安全功能:不应允许其他用户弄乱您的进程。在环境的情况下强制执行此策略的方式是只有父进程才能设置子进程的环境。 不允许子进程设置父进程的环境。假设子进程属于,因此应该允许您对程序执行所需的操作-但由于父进程(您)不属于子进程,因此,不允许孩子破坏父母的环境。

这就是为什么您尝试使用export无效的原因。它实际上有效(变量确实在子shell中创建),但不允许更改其父级的环境(node.js进程)

答案 1 :(得分:0)

在终端中使用export时,它会指示Shell设置环境变量。

当您从代码中调用exec时,您没有在运行这样的shell,原因是提取每个命令的输出将成为一个挑战。

这使export成为忽略的命令。

您可以通过传递option object to execSync:

来解决此问题
execSync('node main.js', {
    env: {
        DB_HOST: 'localhost',
         // More envs...
    }
}