NAME
Env::Modify - affect Perl %ENV from subshell
VERSION
0.02
SYNOPSIS
use Env::Modify 'system', ':readpipe';
$ENV{FOO}="bar";
system('echo $FOO'); # "bar"
system('FOO=baz');
print $ENV{FOO}; # "baz"
# on Perl <=v5.8.8, say "Env::Modify::readpipe" instead
$out = qx(BAR=123; export BAR; echo hello);
print $ENV{BAR}; # "123"
print $out; # "hello";
###
use Env::Modify 'source', ':bash', ':chdir';
open ENV, '>my_env.sh';
print ENV "export MEANING_OF_LIFE=42\n";
print ENV "cd \$HOME\n";
print ENV "cd .cpan\n";
close ENV;
my $status = source("my_env.sh");
print $ENV{MEANING_OF_LIFE}; # "42"
print "Current dir: ",Cwd::getcwd(),"\n"; # "/home/mob/.cpan"
DESCRIPTION
New Perl programmers are often confused about how the system
call interacts with the environment, and they wonder why this code:
system('export foo=bar');
system('echo $foo');
behaves differently from
system('export foo=bar; echo $foo');
or why when they run this code
system("chdir \$HOME/scripts");
system("source my.env");
system("./my_script.sh");
all the environment variables that they carefully set in my.env
are ignored by ./my_script.sh
.
The reason these codes do not meet the new user's expectations is that subshells, such as those launched by system
, receive their own copy of the operating system environment and can only make changes to that local environment.
This module seeks to overcome that limitation, allowing system
calls (and qx()
/readpipe
/backticks) calls to affect the local environment. It uses the clever mechanism in Diab Jerius's Shell::GetEnv module to copy the environment of the subshell back to the calling environment.
FUNCTIONS
system
EXIT_CODE = system LIST
Acts like the builtin "system" in perlfunc command, but any changes made to the subshell environment are preserved and copied to the calling environment.
Like the builtin call, the return value is the exit status of the command as returned by the "wait" in perlfunc call.
When you import the system
command into your calling package (with use Env::Modify ':system'
), Env::Modify
installs the Env::Modify::system
function to the CORE::GLOBAL
namespace (see "Overriding Build-in Functions" in perlsub), making it available anywhere that your program makes a call to system
.
readpipe
readpipe(EXPR)
Env::Modify::qx(EXPR), &qx(EXPR)
backticks(EXPR)
Executes a system command and returns the standard output of the command. In scalar context, the output comes back as a single (potentially multi-line) string. In list context, returns a list of lines (however lines are defined with "$/" in perlvar or "$INPUT_RECORD_SEPARATOR" in perlvar).
Unlike the builtin readpipe
command, any changes made by the system command to the subshell environment are preserved and copied back to the calling environment.
When any of the functions readpipe
, qx
, or backticks
or any of the tags :readpipe
, :qx
, :backticks
, or :all
are imported into the calling namespace, this module installs the Env::Modify::readpipe
function to the CORE::GLOBAL
namespace. As described in "Overriding Built-in Functions" in perlsub, an override for the readpipe
function also overrides the operators ``
and qx{}
. Note that readpipe
was not supported as an overridable function for the CORE::GLOBAL
package until Perl v5.8.9. If your version of perl is older than that, you will need to use function names and not qx[]
or backticks notation to get this module to modify your environment.
See the "RT115330" section for another important caveat about the readpipe
set of functions, and how to structure your use Env::Modify ...
statement to make best use of this module.
readpipe_list LIST
backticks_list LIST
qx_list LIST
Convenience functions to accommodate external commands with shell metacharacters. Like the "readpipe" function, but may take a list of arguments the way that Perl's system LIST
function does. Compare:
$output = readpipe("ls -l \"My Documents\" Videos*");
$output = readpipe_list("ls","-l","My Documents","Videos*");
(See also: https://metacpan.org/pod/distribution/perl/Porting/todo.pod#readpipe-LIST.)
source FILE LIST
Like the shell built-in command of the same name (also called .
in some shells), executes the shell commands in a file and incorporates any modifications to the subshell's environment into the calling environment.
That is, if my_env.sh
contains
FOO=123
NUM_HOME_FILES=$(ls $HOME | wc -l)
export FOO NUM_HOME_FILES
then you could run
use Env::Modify 'source';
source("my_env.sh");
print "FOO is $ENV{FOO}\n"; # expect: "123"
print "There are $ENV{NUM_HOME_FILES} in the home dir\n";
RT115330
"perlbug RT#115330" described an issue with Perl code that sets the *CORE::GLOBAL::readpipe
function, like this module does. This bug was fixed in Perl v5.20.0 and if you are not using an older version of Perl than that, you are not affected by this bug and you may stop reading.
The short version is that the arguments received by the CORE::GLOBAL::readpipe
function are correct when you use the keyword readpipe
to call the function, and they need to be interpolated an extra time when you use backticks or the qx//
construction.
The form of the use
statement should resemble the way that you usually invoke the readpipe
command. If your code literally calls the readpipe
function, then you should load this module with
use Env::Modify ':readpipe';
If your code usually uses the qx!!
construct or backticks to invoke readpipe
, then you should load the module with either
use Env::Modify ':qx';
use Env::Modify ':backticks';
(these two calls are equivalent). This will have the effect of interpolating the input one last time before the input is passed to the shell.
If your code uses both readpipe
and qx{}
/backticks, you can always workaround this bug using fully-qualified function names like Env::Modify::readpipe()
, Env::Modify::qx()
, or Env::Modify::backticks()
. All of these function calls will receive correctly interpolated input.
MODULE VARIABLES
$SHELL
The shell that the Shell::GetEnv module will use to run an external command. This must be a value supported by Shell::GetEnv, namely one of bash
, csh
, dash
, ksh
, sh
, tcsh
, or zsh
. Defaults to sh
.
The value of $SHELL
can also be set by specifing a tag with the shell name when this module is imported. For example, to specify bash
as the shell for this module to use, load this module like
use Env::Modify ':bash';
$CHDIR
If $Env::Modify::CHDIR
is set to a true value, then any change of the current working directory in a subshell will also affect the working directory in the calling (Perl) environment. That is, you can say
chdir "/some/path";
$f = -f "bar"; # -f /some/path/bar
system("cd foo");
$g = -f "bar"; # -f /some/path/foo/bar
You can also enable this feature at import time with the :chdir
tag.
%CMDOPT
A set of options that are passed to the Shell::GetEnv constructor. See the new
method in "METHODS" in Shell::GetEnv.
# don't load startup files (.profile, .bashrc, etc.)
# when system() runs below
local $Env::Modify::CMDOPT{startup} = 0;
Env::Modify::system("FOO=bar; export FOO");
%ENVSOPT
A set of options that are passed to the import_envs
method of Shell::GetEnv. See the import_envs
method in "METHODS" in Shell::GetEnv.
# don't remove entries from Perl environment
local $Env::Modify::ENVSOPT{ZapDeleted} = 0;
source("./script_that_erases_PATH_var.sh");
print "PATH is still $ENV{PATH}"; # not erased
EXPORT
This module has four functions that can be exported into the calling namespace: system
, readpipe
, qx
, and backticks
. As qx
is a Perl language construction and not just a keyword, if you import the qx
function you would either have to use a fully qualified function name or a sigil to use it:
package My::Pkg;
use Env::Modify 'qx';
...
$out1 = qx($cmd1); # calls Perl built-in, not Env::Modify::qx !
$out2 = &qx($cmd2); # calls Env::Modify::qx
$out3 = My::Pkg::qx($cmd3); # calls Env::Modify::qx
The tag :system
exports the system
function into the calling namespace and also sets the CORE::GLOBAL::system
function, so that all system
calls in any package in any part of your script will use the Env::Modify::system
function.
The tags :readpipe
, :qx
, or :backticks
export the readpipe
, qx
, and backticks
functions into the calling namespace, and also set the CORE::GLOBAL::readpipe
function, so that all readpipe
calls, qx//
constructions, or backticks expressions in any package and in any part of your script will use the Env::Modify::readpipe
function. If you are vulnerable to "RT115330" (see above), then you should use :readpipe
if your script generally uses readpipe()
to capture output from external programs and use :qx
or :backticks
if your script generally uses qx!!
or backticks.
The :all
tag behaves like :system
+ :backticks
.
You may also specify the :chdir
tag to enable the "chdir" feature (see $CHDIR
under "MODULE VARIABLES"), or a tag with the name of a shell like :sh
, :bash
, etc. to specify the default shell for this module to run external commands (see $SHELL
under "MODULE VARIABLES").
LIMITATIONS
- Portability
-
Env::Modify
can only work on systems where Shell::GetEnv will work, namely systems where POSIX-y type shells are installed. - Buffering
-
With a regular
system
orreadpipe
/qx
/backticks call, lines from the standard error stream of the external command (and from the standard output stream in the case ofsystem
) are written to the terminal as the external program produces them. Because of the nature of how this module recovers and transfers the environment of the subshell,Env::Modify
functions will hold onto external program output, and not publish it to your Perl script's terminal until the command has completed. This may cause suffering from buffering, and for that, the author of this module apologizes. - Interlaced standard output and standard error
-
In a regular
system
call that writes to both standard output and standard error, lines from the output stream and error stream will often be interleaved on your terminal. Because of the nature of how this module recovers and transfers the environment of the subshell,Env::Modify::system
calls will not interleave error and output this way. All of the standard error output, if any, will be written to the terminal (file descriptor 2, which is usually but not necessarily STDERR), followed by all standard output being written to the terminal (file descriptor 1).
DEPENDENCIES
Shell::GetEnv provides the mechanism for copying a subshell's environment back into the calling environment.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Env::Modify
You can also look for information at:
RT: CPAN's request tracker
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
AUTHOR
Marty O'Brien, <mob at cpan.org>
COPYRIGHT AND LICENSE
Copyright (c) 2016, Marty O'Brien
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
See http://dev.perl.org/licenses/ for more information.