env command does not list SHELL environmental variable - bash

Below is the output of the env command:
[root#machine123 /etc/profile.d] env | grep SHELL
As you can see the output of env does not list the SHELL environment variable.
But when I print $SHELL, it is there:
[root#machine123 /etc/profile.d] echo $SHELL
/bin/bash
What is going on, why is SHELL missing from the env output?

If you want to know your local variables use the set command:
set lets you change or display the names and values of all shell variables and functions
Try set | grep SHELL
env or printenv displays global (or environment) variables, set local ones (which include the environment variables):
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html

If the shell you are running does not export this variable, it will not be visible to subprocesses, including env.
Expecting it to exist and to be set to a useful value (outside of a shell script) is probably not portable. A sane (at least on POSIX) default is to assume SHELL=/bin/sh if it is unset.

Related

$BASH_VERSION vs /usr/bin/env

I run this to check env:
env | grep bash
and then got nothing.
So, I think the variable bash is not set in env. However, in a shell script file:
#!/usr/bin/env bash
echo $BASH_VERSION
I got 5.1.16(1)-release.
It seems contradictory because, on the one hand, I think the variable bash must have been set as the shell script file can be executed in a manner as expected; on the other hand, running env | grep bash, I got nothing.
How could the OS locate the app bash-5.1.16 without an env variable being set?
The $BASH_VERSION is not an environment variable but a shell variable.
You can see defined shell variable with the declare builtin.
declare | grep BASH_VERSION
BASH_VERSION='5.1.4(1)-release'
The env program is used to run a program with modified environment.
Running /usr/bin/env bash without arguments is basically the same as running bash, it's ensure that the program is on the file system and not a shell builtin.

Do you need to include export for environment variables in bash profile / zshrc?

Do you need to include export for environment variables in Bash profile / zshrc?
I'm using Z shell (Zsh) for my terminal and in my .zshrc file I have the two lines:
varOne="foo"
export varTwo="bar"
When I echo either variable (ex: echo $varOne) within the terminal, the correct value is output.
So is there a difference when prefixing the environment variable declaration with export inside the .zshrc file?
So is there a difference when prefixing the environment variable declaration with export inside the .zshrc file?
Yes, one is an environment variable and the other isn't.
The difference doesn't matter (much) to your shell, but to processes started by your shell. Environment variables are inherited by child processes, regular shell variables are not.
~ % foo=3; printenv foo
~ % export foo=3; printenv foo
3
In the first case, printenv has no variable named foo in its environment; in the second case, it does.

Finding all the Enviorment Variables in Bash

I recently got a book on shell scripting in bash. It states to list all the Environment Variables using the printenv command. I've noticed though that this doesn't list all variables, for example $PWD or $REPLY or $SSH_TTY. Is their a complete list I can reference for all of these Environment Variables and their Functions?
Within a shell like bash there are two types of variables; environment variables (Wikipedia) and shell variables. There are a number of predefined shell variables.
You can use the export built-in to "promote" a shell variable to an environment variable, which has the effect of making that variable available to any subprocesses launched from the shell.
As the name implies, printenv only reports the process' environment variables. Variables like PWD or REPLY are shell variables, and thus aren't displayed. As suggested in the comments, invoking set with no arguments will print all variables (environment and shell) available in your current session.
To display a list of the Environment Variables you can use
set
#if you want to see it nicely you can pipe it to more like this
set | more

How to set environment variables in fish shell

Can someone please tell me what's the correct way to set a bunch of environment variables in the fish shell?
In my ~/.config/fish/config.fish file, I have a function to setup my environment variables like so:
function setTESTENV
set -x BROKER_IP '10.14.16.216'
set -x USERNAME 'foo'
set -x USERPASS 'bar'
end
When I type from the command prompt setTESTENV and do a env in the command line, I don't see this information.
Use Universal Variables.
If the variable has to be shared between all the current user Fish instances on the current computer and preserved across restarts of the shell you can set them using -U or --universal. For example:
set -Ux FOO bar
Using set with -g or --global doesn't set the variable persistently between shell instances.
Note:
Do not append to universal variables in config.fish file, because these variables will then get longer with each new shell instance. Instead, simply run set -Ux once at the command line.
Universal variables will be stored in the file ~/.config/fish/fish_variables as of Fish 3.0. In prior releases, it was ~/.config/fish/fishd.MACHINE_ID, where MACHINE_ID was typically the MAC address.
The variables you are declaring are keep in a local scope inside your function.
Use:
set -g -x
Here "g" is for global.
another option is to run:
export (cat env_file.txt |xargs -L 1)
where env_file.txt contains rows of the format VAR=VALUE
this has the benefit of keeping the variables in a format supported by other shells and tools
Environment Variables in Fish
I would like to add that, while #JosEduSol's answer is not incorrect and does help solve the OP problem, -g is only setting the scope to be global, while -x is causing the specified environment variable to be exported to child processes.
The reason the above fails, is because #cfpete is setting the env vars inside a function and the default scope will be local to that function.

What does the 'export' command do?

I happen to run some commands blindly, in order to get things done.
I started to work with Jenkins recently, and then I had to use this export command to run the Jenkins WAR archive. What does the export command do in general, and why do we need to run this command, while running Jenkins (after the Jenkins home is set)?
export in sh and related shells (such as Bash), marks an environment variable to be exported to child-processes, so that the child inherits them.
export is defined in POSIX:
The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands. If the name of a variable is followed by = word, then the value of that variable shall be set to word.
I guess you're coming from a Windows background. So I'll contrast them (I'm kind of new to Linux too). I found a user's reply to my comment, to be useful in figuring things out.
In Windows, a variable can be permanent or not. The term environment variable includes a variable set in the cmd shell with the SET command, as well as when the variable is set within the Windows GUI, thus set in the registry, and becoming viewable in new cmd windows.
E.g., the documentation for the set command in Windows "Displays, sets, or removes environment variables. Used without parameters, set displays the current environment settings."
In Linux, set does not display environment variables. It displays shell variables which it doesn't call/refer to as environment variables. Also, Linux doesn't use set to set variables (apart from positional parameters and shell options, which I explain as a note at the end), only to display them and even then only to display shell variables. Windows uses set for setting and displaying, e.g., set a=5, but Linux doesn't.
In Linux, I guess you could make a script that sets variables on bootup, e.g., /etc/profile or /etc/.bashrc, but otherwise, they're not permanent. They're stored in RAM.
There is a distinction in Linux between shell variables, and environment variables. In Linux, shell variables are only in the current shell, and environment variables, are in that shell and all child shells.
You can view shell variables with the set command (though note that, unlike Windows, variables are not set in Linux with the set command).
set -o posix; set (doing that set -o posix once first, helps not display too much unnecessary stuff). So set displays shell variables.
You can view environment variables with the env command.
Shell variables are set with, e.g., just a = 5.
Environment variables are set with export. Export also sets the shell variable.
Here you see shell variable zzz set with zzz = 5, and see it shows when running set, but it doesn't show as an environment variable.
Here we see yyy set with export, so it's an environment variable. And see it shows under both shell variables and environment variables:
$ zzz=5
$ set | grep zzz
zzz=5
$ env | grep zzz
$ export yyy=5
$ set | grep yyy
yyy=5
$ env | grep yyy
yyy=5
$
Other useful QnAs:
https://unix.stackexchange.com/questions/176001/how-can-i-list-all-shell-variables
https://askubuntu.com/questions/26318/environment-variable-vs-shell-variable-whats-the-difference
Note: One point which elaborates a bit and is somewhat corrective to what I've written, is that, in Linux bash, 'set' can be used to set "positional parameters" and "shell options/attributes", and technically both of those are variables, though the man pages might not describe them as such.
But still, as mentioned, set won't set shell variables or environment variables). If you do set asdf then it sets $1 to asdf, and if you do echo $1 you see asdf.
If you do set a=5 it won't set the variable a, equal to 5. It will set the positional parameter $1 equal to the string of "a=5". So if you ever saw set a=5 in Linux it's probably a mistake unless somebody actually wanted that string a=5, in $1.
The other thing that Linux's set can set, is shell options/attributes. If you do set -o you see a list of them. And you can do for example set -o verbose, off, to turn verbose on (by the way, the default happens to be off, but that makes no difference to this). Or you can do set +o verbose to turn verbose off. Windows has no such usage for its set command.
In simple terms, environment variables are set when you open a new shell session. At any time if you change any of the variable values, the shell has no way of picking that change. That means the changes you made become effective in new shell sessions.
The export command, on the other hand, provides the ability to update the current shell session about the change you made to the exported variable. You don't have to wait until new shell session to use the value of the variable you changed.

Resources