【问题标题】:How to export a shell variable within a Perl script?如何在 Perl 脚本中导出 shell 变量?
【发布时间】:2011-02-27 09:46:34
【问题描述】:

我有一个 shell 脚本,其中包含一个 shell 变量列表,在进入编程环境之前执行。

我想用Perl脚本进入编程环境:

system("environment_defaults.sh");
system("obe");

但是当我进入环境时,变量并没有设置。

【问题讨论】:

    标签: perl unix shell environment-variables


    【解决方案1】:

    不同的sh -c 进程将被调用并且环境变量在这些进程中被隔离。

    调用 environment_defaults.sh 也不会在这些变量将被单独设置为的范围内创建另一个 sh 进程吗?

    或者在导出这些环境变量的情况下启动 Perl 脚本,然后为其所有子进程设置这些变量。

    【讨论】:

      【解决方案2】:

      当您调用第二个命令时,它并没有在您在第一个命令中修改的环境中完成。事实上,没有第一个命令留下的环境,因为用来调用“environment_defaults.sh”的shell已经退出了。

      要在第二个命令中保留第一个命令的上下文,请在同一个 shell 中调用它们:

      system("source environment_defaults.sh && obe");
      

      请注意,您需要使用 source 调用 shell 脚本才能在 当前 shell 中执行其操作,而不是调用新的 shell 来执行它们。

      或者,在每个 shell 的开头修改您的环境(例如,使用 .bash_profile,如果使用 bash),或者在 perl 本身中更改您的环境变量:

      $ENV{FOO} = "hello";
      system('echo $FOO');
      

      【讨论】:

      • 这不起作用,因为 environment_defaults.sh 将使其成为自己的子子实例
      • 谢谢,我会尝试第一个选项。其他两个选项是我试图避免的。
      • @Imre: true,如果只是简单地执行脚本,就会调用一个新的 shell。使用 'source' 在同一个 shell 中执行命令(答案已更新)。
      • 也许你的意思是:system("sh -c 'source environment_defaults.sh; obe'")
      【解决方案3】:

      每个进程都有自己的环境,每次调用“系统”时,它都会运行一个新进程。所以,你正在做的事情是行不通的。您必须在一个进程中运行这两个命令。

      但是请注意,在您的 Perl 脚本存在之后,它设置的任何环境变量都将无法在命令行中为您提供,因为您的 Perl 脚本也是一个拥有自己环境的进程。

      【讨论】:

        【解决方案4】:

        更新:哦,这不是您要求的,但它可能对某人有用。)

        如果安装了GDB,您可以使用以下 hack 设置/修改父 shell 变量(为清楚起见,使用非严格样式):

        #!/usr/bin/perl
        # export.pl
        
        use File::Temp qw( tempfile );
        
        %vars = (
            a => 3,
            b => 'pigs'
        );
        
        $ppid = getppid;
        
        my @putvars = map { "call putenv (\"$_=$vars{$_}\")" } keys %vars;
        
        $" = "\n";
        
        $cmds = <<EOF;
        attach $ppid
        @putvars
        detach
        quit
        EOF
        
        ($tmpfh, $tmpfn) = tempfile( UNLINK => 1 );
        print $tmpfh $cmds;
        
        `gdb -x $tmpfn`
        

        测试:

        $ echo "$a $b"
        
        $ ./export.pl 
        $ echo "$a $b"
        3 pigs
        
        【解决方案5】:

        但是是的!有可能!

        #!/usr/bin/perl -w
        
        use strict;
        
        my $perldumpenv='perl -MData::Dumper -e '."'".
            '\$Data::Dumper::Terse=1;print Dumper(\%ENV);'."'";
        
        eval '%ENV=('.$1.')' if `bash -c "
                source environment_defaults.sh >/dev/null;
                $perldumpenv"`
            =~ /^\s*\{(.*)\}\s*$/mxs;
        
        system("obe");
        

        有点矫枉过正,因为这会运行到 Perl-only-to-dump 环境的分支,但是以安全的方式运行 Perl 绑定环境并且Data::Dumper > 用于发送/存储和检索 Perl 变量的库。

        注意:这不关心安全问题:你必须信任environment_defaults.sh 与主 Perl 脚本处于同一级别!!!

        【讨论】:

          【解决方案6】:

          现在可以使用Env::Modify module 完成此操作

          use Env::Modify 'source';   # or use Env::Modify qw(source system);
          source("environment_defaults.sh");
          ... environment from  environment_defaults.sh  is now available
          ... to Perl and to the following 'system' call
          system("obe");
          

          【讨论】: