Molten Ice
Molten Ice

Reputation: 2911

Create a persistent bash shell session in Node.js, know when commands finish, and read and modify sourced/exported variables

Imagine this contrived scenario:

./main.sh

source ./config.sh
SOME_CONFIG="${SOME_CONFIG}bar"
./output.sh

./config.sh

export SOME_CONFIG='foo'

./output.sh

echo "Config is: ${SOME_CONFIG}"

I am trying to replace ./main.sh with a Node.js powered ./main.js WITHOUT replacing the other shell files. The exported ./config.sh functions/variables must also be fully available to ./output.sh

Here is a NON working ./main.js. I have written this for the sole purpose to explain what I want the final code to look like:

const terminal = require('child_process').spawn('bash')

terminal.stdin.write('source ./config.sh\n')
process.env.SOME_CONFIG = `${process.env.SOME_CONFIG}bar` // this must be done in JS
terminal.stdin.write('./output.sh\n') // this must be able to access all exported functions/variables in config.sh, including the JS modified SOME_CONFIG

How can I achieve this? Ideally if there's a library that can do this I'd prefer that.

Upvotes: 1

Views: 542

Answers (1)

Molten Ice
Molten Ice

Reputation: 2911

While this doesn't fully answer my question, it solves the contrived problem I had at hand and could help others if need be.

In general, if bash scripts communicate with each other via environment variables (eg. using export/source), this will allow you to start moving bash code to Node.js.

./main.js

const child_process = require("child_process");
const os = require("os");

// Source config.sh and print the environment variables including SOME_CONFIG
const sourcedConfig = child_process
  .execSync(". ./config.sh > /dev/null 2>&1 && env")
  .toString();

// Convert ALL sourced environment variables into an object
const sourcedEnvVars = sourcedConfig
  .split(os.EOL)
  .map((line) => ({
    env: `${line.substr(0, line.indexOf("="))}`,
    val: `${line.substr(line.indexOf("=") + 1)}`,
  }))
  .reduce((envVarObject, envVarEntry) => {
    envVarObject[envVarEntry.env] = envVarEntry.val;
    return envVarObject;
  }, {});

// Make changes
sourcedEnvVars["SOME_CONFIG"] = `${sourcedEnvVars["SOME_CONFIG"]}bar`;

// Run output.sh and pass in the environment variables we got from the previous command
child_process.execSync("./output.sh", {
  env: sourcedEnvVars,
  stdio: "inherit",
});

Upvotes: 1

Related Questions