How to actually change/set environment variables from within emacs - linux

In my shell I did: export BLA=foo and then I do echo $BLA and I see foo as expected. I then load up emacs and do M-! for a shell command and do echo $BLA and it's set to something else, bar. So then I run M-x setenv and give it BLA and foo at the prompts but when i do the echo i still see bar. Why would that be and how can I change it? I am trying to do this for some environment variables under which I want to run M-x compile

setenv will modify the environment for the processes emacs launch after you set the value. Running child processes will not be affected.
Thus, doing a (setenv "FOO" "bar") and then M-x shell (provides you have not a running shell yet) will produce a shell with environment variable "FOO" set to "bar".

Your shell in which you've started the Emacs hands over a copy of its environment to its child process (the Emacs), that's how the value is transmitted from the shell to the Emacs. Any change the Emacs then performs with its inherited environment will only affect the Emacs process's environment. There is no way the Emacs's environment can influence the environment of the shell.
If you need to hand information back to the shell, you have to use different techniques like temp files, named pipes, sockets, …
If you just want to check the environment of the Emacs itself, use M-x getenv to look at variables, or use M-! echo $BLA. If this also is showing sth else, then you probably have a special BLA which is automatically set to sth after each command, or which isn't writable at all like RANDOM or similar.

Related

Setting system variable using Node

I have been working on a node script that does the installation of external dependencies and was wondering if its possible to set the PATH variable using Node.
For example, If I want to install Go using script, I can execute command brew install Go and this works but when I do export GOPATH=$PATH, this is never set.
I also tried using process.env but this also does not work. Also my assumption with process is that it must run in a sandbox. So it will not update/ set anything outside.
So the question is, can I do this? If yes, how?
It is not possible in any programming language. At least on Unix (BSD, MacOS, Illumos etc.) and Linux, I'm not sure about Windows.
As a security feature, Unix processes are designed such that they cannot touch the environment of their parent's process. Only the parent process can influence the environment of their children.
When you are on a command line you are running a shell program (either Bash or Korn Shell or TCSH or Fish etc.). When you execute something on the command line such as a node.js script or Google Chrome or Minecraft these programs will be the children to your shell program. On Unix and Linux these child programs inherit their parent's environment.
That is why you can export environment (global) variables and your programs can access them. However, this relationship is one-way and it was designed that way on purpose.
You may notice that in shell scripts you can "save" commands to set environment variables in a file. For example in Bash you sometimes see people do this:
# variables.sh
export HELLO "World"
However, this will not work if you execute the script as a script:
$ bash variables.sh
$ echo $HELLO
<--------------------- nothing is displayed here
the variable is not exported
You sometimes see people do this instead:
$ . variables.sh
$ echo $HELLO
World
And you may wonder how that works. Well.. in some shell languages the dot command imports the script instead of executing the script as a separate process. Think of it like import or require() in javascript.
Of course, Bash does not understand javascript syntax. It also does not understand C++ or Java or Ruby or PHP. It only understands Bash syntax.
So the longer answer is it is not possible in any programming language except for the language of the shell you are using (eg. if you are using Fish you need to write a script in Fish syntax or if you are using Ksh you need to write a script in Korn syntax).

Setting an environment variable through a Perl script [duplicate]

This question already has answers here:
How to Share ENV Variables Among Perl Scripts
(2 answers)
Closed 5 years ago.
I am trying to set an environment variable, LD_LIBRARY_PATH, through a Perl script in the following way:
I have created .profile under /root
.profile has an export command say:
export LD_LIBRARY_PATH=/
My Perl script is test.pl and it has:
#!/usr/bin/perl
system(". /root/.profile");
When I execute ./test.pl, LD_LIBRARY_PATH doesn't change.
What am I doing wrong?
Your current script doesn't even change an environment variable in the Perl script itself. Rather, it invokes a shell as a subprocess; that shell process executes . /root/.profile, which updates $LD_LIBRARY_PATH only in that shell process.
You can change an environment variable in a Perl script (more precisely, in the process running the Perl script) by updating %ENV:
$ENV{LD_LIBRARY_PATH} = '/'; # or some more reasonable value
As perldoc -v %ENV says:
%ENV The hash %ENV contains your current environment. Setting a value in "ENV" changes the environment for any child processes you subsequently "fork()" off.
But that probably still won't do what you want; it won't (and can't) affect the environment of the process that invokes the Perl script (your interactive shell), only the Perl process itself and anything it invokes.
I'll assume you want to update $LD_LIBRARY_PATH in your current interactive shell process. To do that, you can have you Perl script print a shell command that will update $LD_LIBRARY_PATH. Then, rather than simply running your Perl script, you can execute it and then evaluate its output. For example:
$ cat env.pl
#!/usr/bin/perl
use strict;
use warnings;
print "export LD_LIBRARY_PATH=/\n";
$ ./env.pl # just prints the command without executing it
export LD_LIBRARY_PATH=/
$ eval $(./env.pl) # executes the command in the current shell
$ echo $LD_LIBRARY_PATH
/
$
This assumes that your current shell is bash or something similar.
Another option: After modifying %ENV, your Perl script can invoke another command, even a new interactive shell. The new process will inherit its environment from the Perl script. This can be a bit cumbersome, though; for example, if the new process is an interactive shell, it won't inherit unexported variables or history from the parent shell.
(One note, not directly related to your question: The fact that you're messing with /root/.profile implies that you're doing things as root (superuser). This can be dangerous. Use the root account (either by logging into it or via sudo only for things that actually need root privileges. For anything else, use a personal user account.
To change the environment in a Perl script, assign to the %ENV hash:
$ENV{'LD_LIBRARY_PATH'} = '/';
If you want to write a program that's used by a shell to change its environment, the way this is generally done is to have the script write shell commands to stdout. The shell then executes this with command substitution and uses eval to execute the resulting commands:
Perl script:
#!/usr/bin/perl
print 'LD_LIBRARY_PATH=\n';
Shell script:
eval "$(/path/to/perlscript)"
For examples of commands that work like this, see tset and ssh-agent.
system starts a new process, and changing the environment there won't affect the environment in the process of your script (usually—there are generally os-dependent means of changing other processes' environments).
The environment in a perl program is associated with %ENV, which is kind of like (it isn't actually) a tied hash to the environment: changing it will change the environment. Thus:
$ENV{LD_LIBRARY_PATH} = '/';
This can now be done with the Env::Modify module:
use Env::Modify 'source';
source("/root/.profile");
... env settings of .profile are now available to Perl ...
You can't do it.
This is from the Perl FAQ:
In the strictest sense, it can't be done--the script executes as a different process from the shell it was started from. Changes to a process are not reflected in its parent--only in any children created after the change. There is shell magic that may allow you to fake it by eval()ing the script's output in your shell; check out the comp.unix.questions FAQ for details.

How to make declare in a Linux shell script?

I want to put below declare in a shell script: proxy_set
declare -x https_proxy="https://192.168.220.4:8080/"
And then I execute it like below.
$ ./proxy_set
But "export" shows nothing happened.
And in another way if I execute it like this:
$ source proxy_set
Then "export" shows it works!
My question is how can I make it work without additional "source" cmd?
Thanks!
You can't. Setting variables in the environment only affects the environment of that shell and any future children it spawns; there's no way to affect the parent shell. When you run it without the source (or .), a brand new shell is started up, then the variable is set in that shell's environment, and then that shell exits, taking its environment with it.
The source reads the commands and executes them within the current shell as if you had typed them.
So if you want to set environment variables in a script, you have to source it. Alternatively, you can have a command generate shell commands as output instead of running them, and then the parent can evaluate the output of the command. Things like ssh-agent use this approach.
Try just adding:
export https_proxy="https://192.168.220.4:8080/"
Then execute your script normally.

How to access environment variables inside .gdbinit and inside gdb itself?

I am looking to set up the path for the source code when debugging with gdb. I chose to do that with a .gdbinit file.
Basically, it contains a command:
directory="/path/to/src".
However, I would like to be able to specify that command as:
directory="$SOURCESROOT/src"
where SOURCESROOT is an environment variable. And, if possible, being able to do that inside gdb debuuging session too, by entering directory=$SOURCESROOT/folder.
Basically, I am looking to access inside gdb (or inside .gdbinit) the environment variables.
But not the environment of the debugee (set env and so on), but the environment of the gdb itself (ie. of the bash prompt where I type in the first place "gdb program").
While typing shell $SOURCESROOT inside gdb session shows the content of the environment variable, this is quite useless, as I cannot enter: directory=shell $SOURCESROOT.
PS: Anybody found an ideal setup for Linux (Debian) to download the sources with "apt-get source", to update those with some kind of "apt-get update" utopic command and to install them so that gdb will automatically find these sources?
Nevermind, I found how to do it by using Python scripting.
My .gdbinit file is now:
python
import os
gdb.execute('directory' + os.environ['SOURCES'] + '/package_name/src')
end
show directories
(6 year late!)
Don't use .gdbinit for this purpose. It does not expand env vars. Instead, use this commandline to launch gdb:
gdb --init-eval-command="set dir $SOURCESROOT/src"
(gdb) show dir
/path/to/src
FYI this technique can be used to set other critical variables, e.g
gdb --eval-command="set sysroot $SYSROOTDIR"
Which sets sysroot and solib-absolute-prefix in gdb
If you don't want to involve python, then this could work?
"show environment [varname]
Print the value of environment variable varname to be given to your program when it starts. If you do not supply varname, print the names and values of all environment variables to be given to your program. You can abbreviate environment as env."
ftp://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_19.html
Maybe they could be used for conditions as well:
https://www.adacore.com/gems/gem-119-gdb-scripting-part-1
In my case I'd like to set global history in common $HOME/.gdbinit, so I used
set history filename ~/.gdb_history
instead of
set history filename $HOME/.gdb_history

How to set environment variable for everyone under my linux system?

Can I have certain settings that are universal for all my users?
As well as /etc/profile which others have mentioned, some Linux systems now use a directory /etc/profile.d/; any .sh files in there will be sourced by /etc/profile. It's slightly neater to keep your custom environment stuff in these files than to just edit /etc/profile.
If your LinuxOS has this file:
/etc/environment
You can use it to permanently set environmental variables for all users.
Extracted from: http://www.sysadmit.com/2016/04/linux-variables-de-entorno-permanentes.html
man 8 pam_env
man 5 pam_env.conf
If all login services use PAM, and all login services have session required pam_env.so in their respective /etc/pam.d/* configuration files, then all login sessions will have some environment variables set as specified in pam_env's configuration file.
On most modern Linux distributions, this is all there by default -- just add your desired global environment variables to /etc/security/pam_env.conf.
This works regardless of the user's shell, and works for graphical logins too (if xdm/kdm/gdm/entrance/… is set up like this).
Amazingly, Unix and Linux do not actually have a place to set global environment variables. The best you can do is arrange for any specific shell to have a site-specific initialization.
If you put it in /etc/profile, that will take care of things for most posix-compatible shell users. This is probably "good enough" for non-critical purposes.
But anyone with a csh or tcsh shell won't see it, and I don't believe csh has a global initialization file.
Some interesting excerpts from the bash manpage:
When bash is invoked as an interactive
login shell, or as a non-interactive
shell with the --login option, it
first reads and executes commands from
the file /etc/profile, if that file
exists. After reading that file, it
looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that
order, and reads and executes commands
from the first one that exists and is
readable. The --noprofile option may
be used when the shell is started to
inhibit this behavior.
...
When an
interactive shell that is not a login
shell is started, bash reads and
executes commands from
/etc/bash.bashrc and ~/.bashrc, if
these files exist. This may be
inhibited by using the --norc option.
The --rcfile file option will force
bash to read and execute commands from
file instead of /etc/bash.bashrc and
~/.bashrc.
So have a look at /etc/profile or /etc/bash.bashrc, these files are the right places for global settings. Put something like this in them to set up an environement variable:
export MY_VAR=xxx
Every process running under the Linux kernel receives its own, unique environment that it inherits from its parent. In this case, the parent will be either a shell itself (spawning a sub shell), or the 'login' program (on a typical system).
As each process' environment is protected, there is no way to 'inject' an environmental variable to every running process, so even if you modify the default shell .rc / profile, it won't go into effect until each process exits and reloads its start up settings.
Look in /etc/ to modify the default start up variables for any particular shell. Just realize that users can (and often do) change them in their individual settings.
Unix is designed to obey the user, within limits.
NB: Bash is not the only shell on your system. Pay careful attention to what the /bin/sh symbolic link actually points to. On many systems, this could actually be dash which is (by default, with no special invocation) POSIXLY correct. Therefore, you should take care to modify both defaults, or scripts that start with /bin/sh will not inherit your global defaults. Similarly, take care to avoid syntax that only bash understands when editing both, aka avoiding bashisms.
Using PAM is execellent.
# modify the display PAM
$ cat /etc/security/pam_env.conf
# BEFORE: $ export DISPLAY=:0.0 && python /var/tmp/myproject/click.py &
# AFTER : $ python $abc/click.py &
DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
abc DEFAULT=/var/tmp/myproject

Resources