Whats the underlieing concept of environment variables? - node.js

Jolly good evening. I've used Environment Envirables before in Node.js applications, but I feel I havent understood the underlieing concept yet.
Its (in this case) not Node who gives me the ability to set environment variables, right? Is it Linux? Does this concept persist through the whole OS? Do environment Variables have a scope? Can I use them everywhere? Is the pattern always the same? Are they written into the run application, or do some Applications (like node) the ability to actively access them from the inside?
Woulld love to grasp the basic concept.

Environment variables is a functionality provided by the operating system (e.g. Linux).
You can set then in terminal or shell scripts using:
name=value
Or in Node using:
process.env.name = value;
You can access them in shell using:
echo $name
Or in Node using:
console.log(process.env.name);
The scope of the environment variables is the process when they are defined and the sub-processes that it executes.
For example write a Node program called envtest.js:
console.log('Node program:', process.env.test);
process.env.test = 'new value';
console.log('Node program:', process.env.test);
And a shell script called envtest1.sh:
test=value
echo "Shell script: $test"
node envtest.js
echo "Shell script: $test"
Running sh envtest1.sh wil print:
Shell script: value
Node program: undefined
Node program: new value
Shell script: value
As yu can see the Node program doesn't get the value because it wasn't exported. It can set the value and use the new value but it will not be changed in the shell script.
Now, write a different shell script:
test=value
export test
echo "Shell script: $test"
node envtest.js
echo "Shell script: $test"
This time running sh envtest2.sh will print:
Shell script: value
Node program: value
Node program: new value
Shell script: value
It means that the Node program got the value because it was exported this time, it can still change it and use the new value but it works on its own copy, it is not changed in the original shell script that called this Node program.
Instead of:
test=value
export test
You can write:
export test=value
as a shorthand.
A more complicated example, write envtest3.sh:
export test=value
echo "Shell script: $test"
node envtest.js
echo "Shell script: $test"
test=value2 node envtest.js
echo "Shell script: $test"
This time it will print:
Shell script: value
Node program: value
Node program: new value
Shell script: value
Node program: value2
Node program: new value
Shell script: value
Which shows that running test=value2 node envtest.js sets the value of test variable to value2 but only to this invocation of the Node program - the value in the rest of the shell script is still value as it was before.
Those are the 3 kinds of scope of environemnt variables - normally a variable in a shell script is not exported and the programs that you run can't see it. When it is exported then the programs that you run can see it and can modify it but they work on their own copy and it isn't changed in the shell script.
When you run name=value command then the environment variable will be set just for that command but the old value will remain in the rest of the script.
Those are the basics of environment variables and how you can use them in Node.

Related

How to access shell variable value from Node.js?

Let's say there is a variable key1 and its value is 123
key1=123
so when I run the command in linux environment echo $key1, I get output as 123.
Now I have the following gulp task.
const child_process = require('child_process');
....
gulp.task('printKeyValue', function() {
var value1 = child_process.execSync('echo $key1');
console.log(value1.toString().trim());
});
Here, I'm trying to access value of linux variable from nodejs by using Child Process
But when I run the following gulp task, I don't get the desired output.
npm run gulp -- printKeyValue
Instead I get output as $key1 and not 123.
See below screenshot
Other commands like ls & pwd in gulp task gives the desired output.
Can some one please help on this or suggest an alternate way?
You are not exporting the variable. When you just do
key1=123
the variable is not propagated to subprocesses. It will be available in your current bash process, so you can see it when you type echo $key1, but it will not get inherited by the node process. As man bash says:
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following. Unless otherwise noted, the values are inherited from the shell.
[...]
shell variables and functions marked for export, along with variables exported for the command, passed in the environment
You need to either define the variable as exported
export key1=123
or mark an existing variable for export
key1=123
export key1
or launch your node with the modified environment, either via the bash innate capability to do so
key1=123 node code.js
or using /usr/bin/env utility:
env key1=123 node code.js
Once the variable is properly passed to the node process, it will be available both in process.env.key1 and as $key1 in a child process.
EDIT: I just noticed, you actually gave the command you're running; it does not matter, the same logic goes for every executable, whether node or npm or anything else.

korn shell and environment variables

env and start.env that should run in any shell.
It actually does except for KORN where env variable setting is not behaves the way I would expect. So look at example.
file set.env :
#!/bin/bash
export MY_VAR="home" || setenv MY_VAR "home"
file start.sh :
#!/bin/bash
command . ./set.env || source set.env
echo "$MY_VAR"
i can see the print of variable.
but if try to echo it in terminal under ksh, it turned to be not defined.
ksh$ start.sh
home
ksh$ echo $MY_VAR
ksh$
I would expect to see $MY_VAR in my session... any ideas ?
//run under red hat
When you run start.sh, you're executing it as a subcommand, not sourcing it. Consequently, changes it makes to environment variables are scoped to that process and its children; once the process exits, the environment variables it sets die with it.
To portably source the script, executing it in your current shell and thus setting environment variables within that shell, run:
# this works on any POSIX shell, including ksh (and bastardizations such as mksh)
. start.sh
...or, less portably:
# this is a bashism
source start.sh
BTW, as a practice, command . ./set.env is... odd. command prevents execution of shell functions, but any environment where a function named . is defined is arguably a buggy environment. Consider . start.sh alone.

shell script - how to use variables for a shell script without defining the variable in the script

Raspbian (Jessy) - root#Raspberry Pi - Putty
In the Terminal i type in
finalanswer=0
now i got a script with this code
#!/bin/bash
source /lib/lsb/init-functions
echo $finalanswer #just as a test
if [ ! "$finalanswer" = "0" ]
then
rm -r mnt/objects/all
log_warning_msg "All Files has been deleted" || true
touch its_over.txt
else
let finalanswer=1
log_action_msg "Var finalanswer was 0. setting back to 1" || true
fi
there is a cronjob that starts this script every hour
sooo. somewhere there must be an error.
because he is reading the Variable $finalanswer as nothing.
that means variables that has been defined outside of this script will not work?
how do i fix this?
Shell variables are not inherited by child processes. If you want a variable to be inherited, it has to be an environment variable. You create environment variables using the export command.
export finalanswer=0
or
finalanswer=0
export finalanswer
You can also export a variable just for the duration of a command by putting the assignment at the beginning of the command:
finalanswer=0 /path/to/script
Note that variables you assign in your shell will not be accessible to cron jobs. Variables can only be exported to processes that are descended from the shell, and processes run by cron are not related to your shell process. If you want to set a variable for use in a cron job, you can put the assignment into the crontab file itself.
You can define a variable for a single command by placing its definition before the command you wish to run:
$ VARIABLE=hunter perl -E 'say $ENV{VARIABLE}'
hunter
you can do the same thing for a cron entry:
*/10 * * * * VARIABLE=hunter <command>

Difference with running a script using source and ./ [duplicate]

csh:
set a=0
echo "a is $a"
when i do ./my_script.csh output is:
a is
when i do source my_script.csh output is:
a is 0
Why is it so . As i know that ./ execution uses new shell.
That's right, ./my_script.csh starts a new shell, and uses the #! that you should have at the top of the file to select which shell to run (which should be csh in this case).
source my_script.csh runs the script in the current shell.
If the script is incorrectly run in, for example, the bash shell, set a=0 is not the syntax for setting an environment variable in bash, so the code won't work as you expected, because you're using the wrong shell.
Take a look at the #! at the top of the file. Is it correct?
check if variable "a" is set in your current shell:
set | grep '^a='
Remember that once you source script to your current shell,
all it's global variables are there until unset or you exit the current shell.
You may want to start a new shell, source the script, end exit shell to perform valid tests.
I don't know the context of your problem, but you may want to export some key variables to have their copies in every subprocess.

incrementing an environmental variable

I need to increment an environmental variable by these steps:
envar=1
export envar
sh script_incrementation
echo $envar
where script_incrementation contains something like this:
#! /bin/sh
envar=$[envar+1] #I've tried also other methods of incrementation
export envar
Whatever I do, after exiting the script the variable remains with its initial value 1.
THanks for your time.
A shell script executes in its own shell, so you cannot affect the outer shell unless you source it. See this question for details of that discussion.
Consider the following script, which I will call Foo.sh.
#!/bin/bash
export HELLO=$(($HELLO+1))
Suppose in the outer shell, I define an environmental variable:
export HELLO=1
If I run the script like this, it run inside its own shell and will not affect the parent.
./Foo.sh
However, if I source it, it will just execute the commands in the current shell, and will achieve the desired affect.
. Foo.sh
echo $HELLO # prints 2
Your script can not change the environment of the calling process (shell), it merely inherits it.
So, if you export foo=bar, and then invoke sh (a new process) with your script, the script will see the value of $foo (which is "bar"), and it will be able to change its own copy of it – but that is not going to affect the environment of the parent process (where you exported the variable).
You can simply source your script in the original shell, i.e. run
source increment_script.sh
or
. increment_script.sh
and that will then change the value of the variable.
This is because sourceing a script avoids spawning a new shell (process).
Another trick is to have your script output the changed environment, and then eval that output, for example:
counter=$[counter+1]
echo "counter=$counter"
and then run that as
eval `increment_script.sh`

Resources