问题
Perl has access to some environment variables:
> echo $HOST
xtt006
> perl -E 'say $ENV{HOST}'
xtt006
> perl -E 'say `echo \$HOST`'
xtt006
But apparently there's another class of environment variables that aren't in the ENV hash:
> echo $env
opsd
> perl -E 'say $ENV{env}'
(no response from Perl)
> perl -E 'say `echo \$env`'
(no response from Perl)
What's up with that? Is there another technique by which Perl can obtain the value of $env?
回答1:
Try export
ing your variable from the shell. This will move it from the shell's variable list to the environment that all subprocesses will be able to see.
export env
perl -E 'say $ENV{env}'
This should get it to show up.
回答2:
From %ENV in perlvar (my emphasis)
The hash
%ENV
contains your current environment.
The environment is inherited from the process that started the Perl process, here the shell.
However, shell variables can be local, which aren't passed to child processes, or global, that form the environment and are inherited by child processes. The global ones are mostly read from configuration files at startup, but if they are to be added later then they need be exported
A variable created like the ones in the example above is only available to the current shell. It is a local variable: child processes of the current shell will not be aware of this variable. In order to pass variables to a subshell, we need to export them using the
export
built-in command. Variables that are exported are referred to as environment variables. Setting and exporting is usually done in one step:export VARNAME="value"
(my emphasis) By your description it seems that $env
is added as a local variable (with set
), which then also need be exported (export env
) in order to be seen in the one-liner.
Environment variables can be listed with env
or printenv
, while set
lists all variables, both local and environment ones.
The above refers to the bash
shell. The notion of "environment" is the same in other shells, and the same reasoning applies there as well; for a variable to be seen in child processes we need to make it global ("environment variable"). The difference is in how to do this.
In csh
/tcsh
use
setenv env "value"
instead of set var = "value"
, what would create a local variable.
Apart from using a global ("environment") variable instead of a local one, one can pass the variable to Perl code. See this post and this post for examples of doing that with one-liners. If an actual script is invoked then make it take arguments; the standard, and nicest, way is with Getopt::Long,
This isn't a special requirement on the users; they use your script and need to invoke it suitably.
回答3:
Just like Perl has private variables (my $x
) and environment variables ($ENV{Y}
), so does the shell.
$ perl <<'.'
my $x = "x";
$ENV{Y}="Y";
system 'echo "<$x> <$Y>"';
.
<> <Y>
$ sh <<'.'
x=x
export Y=Y
perl -le'print "<$x> <$ENV{Y}>";'
.
<> <Y>
$ csh <<'.'
set x x
setenv Y Y
perl -le'print "<$x> <$ENV{Y}>";'
.
<> <Y>
Having support for private variables is a good thing, not a strange thing.
In your example, $HOST
is an environment variable (uppercase by convention), while $env
is a private variable (lowercase by convention).
sh
and bash
These shells use the same mechanism to assign to private variables and environment variables.
To create an environment variable, one promotes a private variable to an environment using export
.
VAR=val
export VAR
perl -e'...$ENV{VAR}...'
or
export VAR
VAR=val
perl -e'...$ENV{VAR}...'
The promotion and assignment can be combined.
export VAR=val
perl -e'...$ENV{VAR}...'
The above approaches change the environment for the shell, and all subsequent children it creates. The following approach can be used to change a specific child's environment:
VAR=val perl -e'...$ENV{VAR}...'
That approach can also be used to effectively promote a private variable:
var=val
VAR="$var" perl -e'...$ENV{VAR}...'
csh
and tcsh
These shells use different syntax for setting private variables and environment variables.
To set a private variable, one uses set
.
set var val
To set an environment variable, one uses setenv
.
setenv VAR val
perl -e'...$ENV{VAR}...'
The above approaches change the environment for the shell, and all subsequent children it creates.
来源:https://stackoverflow.com/questions/55752593/weird-environment-variables-that-arent-in-perls-env-hash