0

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.

Molten Ice
  • 2,715
  • 1
  • 27
  • 37
  • https://unix.stackexchange.com/q/38205 – root Mar 07 '21 at 05:23
  • It would help if you edit the question to add some more information on why the environment needs to be edited from JS. – root Mar 07 '21 at 05:25
  • The real reason is I want to move away from shell scripts, at least those in my control. I want to replace them with JS. The contrived example demonstrates the problem I have where I own *. /main.sh* but not the other 2 files. I also don't understand how your linked stack exchange could help here. – Molten Ice Mar 07 '21 at 09:45
  • A process (node.js) can't change environment variables of another running process (bash). I suspect it's not a real requirement, which is why you should provide more context. – root Mar 07 '21 at 22:18

1 Answers1

1

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",
});
Molten Ice
  • 2,715
  • 1
  • 27
  • 37
  • Maybe actually there is not a way to get it working like a persistent sh/bash session to send commands, but one can simply just create a .sh file and then run it through nodejs child_process.exec so it CAN have sourcing or anything else that needs to be did in a single sh/bash session, will be harder to implement proper error handling and so you have knowledge about sh/bash coding, but it works. +1 – Máxima Alekz Jun 01 '22 at 18:24