通过Perl脚本设置环境变量

6
我正在尝试通过Perl脚本设置一个环境变量LD_LIBRARY_PATH,做法如下:
我在/root下创建了.profile文件。 .profile文件中包含一个export命令,例如:
export LD_LIBRARY_PATH=/

我的Perl脚本是test.pl,它包含:

#!/usr/bin/perl
system(". /root/.profile");

当我执行./test.pl时,LD_LIBRARY_PATH没有改变。我做错了什么?

1
你不能改变另一个进程的环境。 - Barmar
3
您只能更改进程本身的环境。这个环境将会被它所产生的子进程继承。由于system()在Perl的子进程中运行shell命令,任何它所做的环境更改都不会影响Perl本身,也不会影响调用Perl的shell。 - Barmar
那么我该如何在Perl脚本中更改环境变量? - user2848437
5个回答

12

您当前的脚本甚至没有改变Perl脚本本身中的环境变量。相反,它作为子进程调用了一个shell;该shell进程执行. /root/.profile,仅在该shell进程中更新$LD_LIBRARY_PATH

您可以通过更新%ENV在Perl脚本中(更准确地说,在运行Perl脚本的进程中)更改环境变量:

$ENV{LD_LIBRARY_PATH} = '/'; # or some more reasonable value

根据perldoc -v %ENV的说法:

 

%ENV哈希变量包含了你当前的环境。在“ENV”中设置一个值,会更改任何你随后"fork()"出来的子进程的环境。

但是这可能仍然无法满足您的需求;它不会(也不能)影响调用Perl脚本的进程(您的交互式shell)的环境,只能影响Perl进程本身和它调用的任何内容。

我假设您想要更新当前交互式shell进程中的$LD_LIBRARY_PATH。为此,您可以让Perl脚本打印一个shell命令,该命令将更新$LD_LIBRARY_PATH。然后,您可以执行这个脚本并评估其输出,而不仅仅是运行它。例如:

$ cat env.pl
#!/usr/bin/perl

use strict;
use warnings;

print "export LD_LIBRARY_PATH=/\n";
$ ./env.pl          # just prints the command without executing it
export LD_LIBRARY_PATH=/
$ eval $(./env.pl)  # executes the command in the current shell
$ echo $LD_LIBRARY_PATH 
/
$ 
这假设你目前使用的是bash或类似的shell。
另一个选择:修改 %ENV 后,你的Perl脚本可以调用另一个命令,甚至是一个新的交互式shell。新进程将从Perl脚本继承其环境。不过这可能有点繁琐;例如,如果新进程是一个交互式shell,则不会从父shell继承未导出的变量或历史记录。
(一个注意事项,与你的问题无直接关系:你在处理 /root/.profile 意味着你正在以root(超级用户)身份执行操作。这可能很危险。只为那些实际需要root权限的事情使用root帐户(通过登录或sudo)。对于其他任何事情,请使用个人用户帐户。)

嘿,我能否使用系统命令从另一个Perl脚本test.pl中调用eval($./env.pl)?如果可以的话,你能告诉我如何操作吗? - user2848437
@user2848437:不是用那种语法。Perl确实有一种语法来捕获外部命令的输出,使用反引号或qx/string/perldoc perlop并搜索“Quote-Like Operators”)。它还有一个eval函数(perldoc -f eval)--但当然Perl的eval需要一个带有Perl语法而非shell语法的参数。但是有更好的方法从Perl脚本中调用Perl代码:将代码放入模块中并调用它,或者只需将代码复制到您的脚本中。 - Keith Thompson

5

system 命令会启动一个新的进程,在其环境变量中做的更改不会影响到您的脚本进程的环境变量(通常情况下如此——一般有特定于操作系统的方式来更改其他进程的环境变量)。

在 Perl 程序中,环境变量与 %ENV 相关联,它有点像一个绑定到环境变量的哈希表:更改它会更改环境变量。因此:

$ENV{LD_LIBRARY_PATH} = '/';

5
要在Perl脚本中更改环境,请将值赋给%ENV哈希表:
$ENV{'LD_LIBRARY_PATH'} = '/';

如果你想编写一个程序,用于被shell用来更改其环境变量,通常的做法是让脚本将shell命令写入标准输出。然后shell使用命令替换执行该脚本,并使用eval执行生成的命令:

Perl脚本:

#!/usr/bin/perl
print 'LD_LIBRARY_PATH=\n';

Shell脚本:

eval "$(/path/to/perlscript)"

要查看与此类似的命令示例,请参见tsetssh-agent


#!/usr/bin/perl $ENV{'LD_LIBRARY_PATH'} = '/'; 即使在test.pl中设置并执行./test.pl,LD_LIBRARY_PATH仍然保持不变。 - user2848437
这是因为在 Perl 脚本中更改环境不会对启动 Perl 脚本的 shell 环境产生任何影响。 - mob
你问"如何在Perl脚本中更改环境变量?"我的回答是在Perl脚本内部更改环境,而不是更改父shell中的环境。正如我在评论中所说,并且其他人在他们的回答中解释过,你无法更改另一个进程中的环境 - 你只能在自己的进程中更改它,并且它将被子进程继承。 - Barmar

3
现在可以使用Env::Modify模块完成此操作:
use Env::Modify 'source';
source("/root/.profile");
... env settings of .profile are now available to Perl ...

1

你做不到。

这段内容来自Perl FAQ:

严格来说,它是做不到的——脚本在执行时与启动它的shell进程不同。对进程所做的更改不会反映在其父进程中,只会反映在任何在更改之后创建的子进程中。有一些shell技巧可以通过在shell中eval()脚本的输出来模拟它;请查看comp.unix.questions FAQ以获取详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接