In windows cmd I could echo any environmental variable with echo %VARIABLENAME%, such as
But in powershell, this behavior is inconsistent and I could not understand. For certain variables like $HOME I could do the same thing (echo $VARIABLENAME) as in windows cmd.
But for some other variables I could not simply echo but have to use .NET's class methods, such like
I would like to:
Understand the difference between Powershell and windows cmd. Why they behave differently when accessing and printing environmental variables.
Understand why certain variable is echolable while others are not in powershell. What is the rule behind that.
I am new to powershell. The purpose of this question is not just getting the variable printed, but understanding how things work in powershell and the difference between windows cmd, so that I could better use it.
PowerShell exposes environmental variables via the $Env: scope (you can read more about scopes here)
So to access the USERPROFILE environmental variable, you could do the following (note, I'm using Write-Host in place of echo here, see this answer for details on the difference between the two):
Write-Host $Env:USERPROFILE
PowerShell also exposes a number of automatic variables and these are made available to all scripts and commands.
$HOME for example is one such automatic variable.
For further information on these, see Automatic Variables
Related
I have created a simple .bat file. In this batch file i have a variable named urlExample which is equal to "example.com".
In the same batch file i want to use this variable urlExample in a powershell command.
Specifically, consider the following code:
#echo off
set urlExample = "example.com"
powershell -ExecutionPolicy Bypass -Command "& {$WebClient = New-Object System.Net.WebClient;$WebClient.DownloadFile($urlExample,"C:\.....somePath")
How could i achieve using the urlExample inside the WebClient command?
P.s. I don't want to simply put the url in the DownloadFile's first argument. I want to pass it with a batch variable.
Thanks in advance
In cmd.exe, all variables are also environment variables, such as %urlExample% in your case, and child processes - such as a call to powershell.exe, the Windows PowerShell CLI, inherit environment variables.
By contrast, PowerShell also has shell(-only) variables (e.g., $urlExample, limited to that session only), whereas environment variables must be accessed via the env namespace (e.g. $env:urlExample - see the conceptual about_Environment_Variables help topic).
While you can use string interpolation on the cmd.exe side to "bake in" the values of cmd.exe-defined environment variables, by embedding %urlExample% in the -Command argument, it is more robust to let PowerShell access the environment variable, by referencing $env:urlExample.
Therefore:
#echo off
:: Note: No spaces around "=", double-quote the name *and* the value.
set "urlExample=example.com"
:: Note the reference to $env:urlExample
:: Embedded " chars. are escaped as \"
powershell -ExecutionPolicy Bypass -Command "$WebClient = New-Object System.Net.WebClient; $WebClient.DownloadFile($env:urlExample, \"C:\.....somePath\")"
Note:
-ExecutionPolicy Bypass isn't strictly needed in this case, given that no execution of a script file is (.ps1) is involved here (whether directly with -File or indirectly, as part of a -Command argument).
However, given that the effective execution policy also applies in less obvious scenarios when you use -Command (the default parameter of powershell.exe)[1] - such as (possibly implicitly) loading a module that is either a script module (*.psm1) and / or contains formatting / type-definition data (*.ps1xml) - using -ExecutionPolicy Bypass is a good habit to form to ensure predictable execution, assuming that you trust the code you're invoking.
As Compo points out, another good habit to form to ensure a predictable execution environment is to use -NoProfile, which bypasses loading of PowerShell's profile files. In addition to preventing potentially unnecessary / unwanted modifications of the execution environment by the profiles, bypassing profile loading also speeds up the command.
[1] Note that pwsh, the PowerShell (Core) CLI, now defaults to -File.
I understand from my googling that on *nix systems you can use the export command to set a temporary environment variable for the current session. What's the Windows equivalent for the plain old CMD shell?
I finally figured out that SET is the equivalent of export.
Furthermore, to reference the variable, it needs to be surrounded by percent signs:
SET MY_VARIABLE=42
echo %MY_VARIABLE%
SET documentation: ss64.com/nt/set.html
I've set some environment variables in /etc/profile, I can access them from bash, but for some reason I cant get them from Go.
/etc/profile:
...
TEST_ENV=test_me
I can access it from bash:
echo $TEST_ENV
test_me
I can't access this variable from GO
os.Getenv("TEST_ENV") // returns ""
If I list the available environment variables with
os.Environ()
I don't see the variable I'm looking for, but there a few variables that might help:
SHELL=/bin/sh
USER=root
LOGNAME=root
I guess my problem is related to different sessions and shells, so I even tried running
exec.Command("source /etc/profile")
and get the variables after, but it still returns nothing.
Can you give me some tips how to get environment variables if they're set in /etc/profile? I'd prefer getting them from that file, but if necessary, I can put the variables in a different place as well.
When you set an environment variable in bash, by default it isn't exported. Only exported environment variables are passed along to processes created by the shell (i.e., programs that you run). Try export TEST_ENV=test_me.
Assuming I have the following set as system environment variables in Windows 7
FOO = foo
path = ...;%FOO%/bin
Take the following example run in cmd
set FOO=bar
start cmd
echo %FOO%
//bar
echo %path%
//...;foo/bin
The path environment variable did not re evaluate itself upon launch of cmd, however the new FOO variable did stick. How can I get path to reevaulate itself based on the new FOO variable set in the parent command terminal?
EDIT: I'm looking for path to become ...;bar/bin
There is no "command line equivalent of opening cmd.exe from the desktop or start menu" that reproduces the behavior you care about. Environment variables are inherited from the parent process.
The shell reads the registry and performs interpolation (using its own environment, which is the process of being read from the registry, and knows nothing of variables you set in a command interpreter), which is why updates to the registry settings are reflected in a cmd.exe launched from the shell.
If you launch a new cmd.exe from a running cmd.exe, you won't get the shell behavior, and you will get the existing environment inherited. There's nothing in Windows that uses variables in a command interpreter to interpolate the registry settings. The code responsible for reading the environment from the registry is completely unrelated to cmd.exe... it is in explorer.exe (or probably one of the shell DLLs used by explorer).
This answer, which uses VB Script to read the registry and construct a batch file, is as good as you can get. I haven't tested whether interpolation is performed in the registry-access COM component (Environment("System") method on a WScript.Shell object) used by VB script, or if the environment variable references survive into the batch file and are interpolated during batch processing. So you may be confounded by the order of evaluations and variable assignments, in which case you'd better adapt the script to fetch just the PATH setting itself and leave all other variables alone.
I also found this to be useful
set path=%path:foo/bin=bar/bin%
Not as dynamic as I wanted but it works to replace a portion of a variable.
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.