Accessing environment vars from Ruby using a .env (dotenv) file in zsh - ruby

I'm using the oh-my-zsh dotenv plugin, which loads .env file, if it exists, whenever I cd into a project directory.
I know it works because I can see my custom environment vars set when I run the set cmd.
I can can also echo my custom environment variable from command line:
$ echo $FOO
'foo'
However, I cannot access this environment variable via the env command or Ruby:
$ irb
2.4.1 :001 > ENV['FOO']
nil
How can I make sure environment variables loaded from my .env are accessible from Ruby?

Contrary to what is stated in the documentation of dotenv, you actually need to use the export keyword within the .env file in order to make the parameters available to the environment, e.g.
export FOO=foo
The only exception would be, if the parameter was already an environment variable. For example if it had been exported in ~/.zshrc or if it was already part of the environment zsh got when it started (e.g. PATH or HOME).
All dotenv does is automatically sourcing any .env file when changing into a directory. There is no additional "magic". That means .env needs to be a valid zsh script and its content is run in the context of the current shell session (essentially as if you typed it manually).
It also means that the usual rules apply. That is, just settings parameters makes them available to the current shell context only. In order to make them available as environment variables they need to be exported (either before, during or after being set). So unless a parameter has already been exported before, export is not really "optional" in .env.

Related

Where default PATH environment variable is defined

I've written a simple experiment which consists of cpp and shell. The main thing that cpp does is execve("./test.sh", NULL, NULL);, and shell tries to output environment variables as follows:
printenv
echo "PATH: $PATH"
It's quite expected that the environment is empty since I've sent no environment variables, but I get the following output:
PWD=/home/user/code/security_playground/display_path
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
So, first of all, the environment is not empty. Thus, the first question is how the environment is populated? What are defaults and minimal environment you could possibly get and where is it defined (if defined in config, etc.)?
Second question is where did PATH emerge from. It's not printed by printenv, but it's there if I print it with echo, and test.sh is still capable of calling utilities. Brief googling gave me an idea of /etc/environment, but it's contents is different:
└─$ cat /etc/environment
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
Which, by the way, is surprisingly empty. Why?
I do realize that much of that should be somewhere in docs, but all my googling lead me to quite generic environment descriptions, so any answers or search hints are welcome.
Where default PATH environment variable is defined
It depends. On the distribution, on the shell, on the environment, on OS, on configuration files.
I have some systems at hand, I see:
ArchLinux adds to PATH in /etc/profile.
OpenSuSE has yet a different code that adds to PATH from /etc/profile
CentOS7 has has yet a different code in /etc/profile
I suspect that each distribution places files in slightly different places, they will ship with slightly different configuration.
how the environment is populated?
Bash has DEFAULT_PATH_VALUE that is used when PATH is not set. But don't look at the default value too much - package distrbutors overwrite it.
There is /etc/environment (and pam_env.conf) that are read by PAM on login. So when you login. But not when you chroot.
The is /etc/profile and ~/.profile files read by the shell. These scripts may read other files. So usually there is drop-in dir /etc/profile.d/*.
In bash there is /etc/bashrc or /etc/bash.bashrc /etc/bash.login /etc/bash.logout or similar and user configuration files ``~/.bashrcetc. In bash also/etc/bash_completion.dand all scripts in/usr/share/bash_completionare also sourced, when completion is enabled. BUT these files are for Bourne shell - there are also other shells, notablyzshandcsh`, and people use them and they have different syntax and different set of startup files.
Each of these scripts can manipulate PATH, it can reset it, append to it, do whatever it wants to it.
And there are also different set of files read on login/non-login + interactive/non-interactive shells, and these files can include each other (it's common to have .bash_profile or other files that just source .bashrc or similar).
What are defaults
The /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin looks like a good default that should be safe on any linux.
by the way, is surprisingly empty. Why?
My /etc/environment file is just empty and has only the default comment in linux-pam package. /etc/environment has a very simple syntax and is read by pam (there may be no pam on your system...). To modify shell environment, one would prefer shell files - so /etc/profile is the place to keep system modifications. Also /etc/environment has simple key=value syntax, wherea's in /etc/profile you have, well, shell. And /etc/environment is read on login by PAM - so putting PATH just there would break I think for example docker, it just runs a shell in chroot, there is login.
To quote the POSIX specification:
If PATH is unset or is set to null, the path search is implementation-defined.
One way way an implementation can behave when PATH is initially unset is to simply set it to a hardcoded value. (It could also refuse to run any external executables at all, or throw monkeys at your face; "implementation defined" means the standard takes no position on what the computer does in the circumstance at hand, so it's unwise to make any assumption about what that behavior will be).
Similarly, for PWD, with emphasis added:
The value is set by the cd utility, and by the sh utility during initialization
...so initializing this at shell startup time is explicitly mandated by the standard.

Environment variable cut off at the #

OS: Ubuntu 18.04
I am trying to use my /etc/environment file, to export some variables, to be used by Rails.
cat /etc/environment
....
RAILS_ENV='test'
RAILS_DB_PWD='X35i#98n'
However, when I try:
echo $RAILS_DB_PWD
I get:
X35i
It looks like it's cut off at the #. I would like to include # in the password, and make it available system wide, not just from my local bash shell.
However, if I add this to my .bashrc file, it works fine
Any ideas?
What does shopt show?
echo "${RAILS_DB_PWD}"
Should prevent the shell from interpreting the # that way.
As Elias Soares said in his comment, /etc/environment is not a good place to set a variable with embedded #. Set it in your bash initialization file (for instance /etc/profile) as
RAILS_DB_PWD='X35i#98n'
and it should work. If you intend to span (non-bash) subshells or run programs you are supposed to use this environment variable, don't forget to export it.

Using environment variables when adding paths on MacOS

I've found myself with the need to add a new path permanently in all terminal sessions on my Mac. Specifically I want to add the contents of my $GOPATH/bin to my $PATH.
So far I think my options are to either:
Add it to my $HOME/.bash_profile file using export syntax.
Create a file containing the path to add in the /etc/paths.d directory.
I've settled on option 2, because I like the idea of just adding files with one line in whenever I want a new path added permanently.
I have tried adding in a file /etc/profile.d/gopath containing ~/code/go/bin. This works. However, what I'd like to do is evaluate the environment variable, $GOPATH/bin such that if I decide to change my $GOPATH I only have to change the variable. However, that just adds the literal words "$GOPATH/bin" to my path, it doesn't actually add the directory to my path. The $GOPATH bash environment variable is currently set in my ~/.bashrc file.
Some questions:
Why doesn't the $ syntax evaluate in the $PATH or setting of $PATH? Is that not bash?
What comes first, the inclusion of ~/.bashrc, ~/.bash_profile or /etc/profile.d? It is reasonable of me to think that the environment variable would be there when setting the $PATH?
How can I have this environment variable be evaluated and substituted if it is feasible?
Thanks for your help. All my searches don't seem to come up with the above answers.

Where could I find docker-standard environment variables like DOCKER_HOST?

I'm using docker-maven-plugin. And it said -
"By default the plugin will try to connect to docker on localhost:2375. Set the DOCKER_HOST environment variable to connect elsewhere.
DOCKER_HOST=tcp://<host>:2375
Other docker-standard environment variables are honored too such as TLS and certificates.".
After I protect the Docker daemon socket reference to https://docs.docker.com/engine/security/https/. I think I need to set some variables like DOCKER_TLS_VERIFY="1" and also variable which is used to locate ca.pem file. So where could I find these docker-standerd environment variables?
You would find (and set) them on the same user that is running the docker-client.
EG:
nick#primestorage01:~$ set | grep DOCKER
DOCKER_HOST=terrorbyte:2376
DOCKER_TLS_VERIFY=true
You can do that many ways for an interactive login. One way is via a .bashrc file. (assuming you are using bash)
In .bashrc, you can add these lines:
#docker
export DOCKER_HOST=terrorbyte:2376
export DOCKER_TLS_VERIFY=true
If this is some sort of automation, depending on your methodology .bashrc won't be called (Specifically, if it's a non interactive shell such as via ssh host COMMAND. In this case, you'll need to set the environment variables another way.
PS, make sure you also put the certificates in the expected directory to make your life easier. The expected directory is ~/.docker

The /etc/environment file is not executing certain commands

Given below are the contents of my /etc/environment file
alias ...="cd ../../"
alias ls="ls -al"
export blah="blah blah"
When I start new terminal session and change to sudo user as sudo su, only the export command has run, which I am able to verify using env. The aliases are not set.
If I run source /etc/environment the aliases get set as expected. Am I missing something? I also read that /etc/environment is only read when the system boots. Is that true?
I am running on RHEL 7.
The /etc/environment is intended for setting environment variables for every user on login. Therefore you don't need to use export in this file.
Adding alias into this file won't work, because this file is not a shell script and only accepts variable=value pairs.
/etc/environment is used by the PAM-env module and is agnostic to
login/non-login, interactive/non-interactive and also Bash/non-Bash,
so scripting or glob expansion cannot be used. The file only accepts
variable=value pairs.
It's not possible to export aliases or set them globally - they need to be set again in every shell instance.
The file you want to use is ~/.bashrc in a home directory of a user. This file gets executed every time a user opens a bash shell. So aliases and variables set in this file will have effect only on that shell.
You can also use /etc/bash.bashrc which is System-wide .bashrc file for interactive bash shells.
The reason why the export in your /etc/environment worked and actually created and env variable is that the pam-env parser specifically ignores export keyword to avoid confusion for people who don't know that /etc/environment is not a shell script.
You can see that in pam_env.c source code
/* skip over "export " if present so we can be compat with
bash type declarations */
if (strncmp(key, "export ", (size_t) 7) == 0)
key += 7;
Its available for example here - Linux-PAM/pam_env.c v0.79. See line 00234.

Resources