【问题标题】:can we source a shell script in perl script我们可以在 perl 脚本中获取 shell 脚本吗
【发布时间】:2010-09-09 10:16:32
【问题描述】:

我们可以在 perl 脚本中获取 shell 脚本吗??

示例: 方案一:

cat test1.sh
#!/bin/ksh
DATE=/bin/date

程序 2:

cat test2.sh
#!/bin/ksh
. ./test1.sh  
echo `$DATE`

方案 3:

cat test3.pl
#!/usr/bin/perl
### here I need to source the test1.sh script
print `$DATE`'

如何在 perl 中获取 shell 以在我执行 test3.pl 时打印日期

谢谢 拉古

【问题讨论】:

  • 有什么理由不想为此使用 Perl 的日期时间模块?
  • @ghostdog74 你甚至不需要模块。标量上下文中的localtime 函数生成几乎相同的字符串:perl -le 'print scalar localtime',您只需要获取时区,它们将是相同的。
  • 嘿日期只是一个例子......它可以是代替日期的任何东西(ls,chown,echo .....)无论第一个文件中的命令是什么我需要来源到 perl;

标签: perl


【解决方案1】:

你做不到

system("source src.sh");

system() 启动一个新的子 shell,您的环境变量不会传递到运行 Perl 脚本的 shell。即使您的 shell 脚本导出变量,它也会将它们导出到子 shell,而不是你的实际外壳。

一种解决方案是编写一个包装脚本

  1. 首先获取 shell 脚本,然后
  2. 运行 Perl 脚本

【讨论】:

  • 这是我通常做的,但如果你想根据你正在做的事情来获取不同的文件,它就不起作用了。例如,假设您有三个数据库并且需要不同的环境来访问它们。您事先不知道需要连接到哪个数据库。在这种情况下,包装器方法会失败。
【解决方案2】:

我不知道这会有所帮助,但我觉得有必要想出一种用 Perl 编写它的方法。我的意图是让 Perl 运行一个 shell 脚本,并将它设置的任何 shell 变量分配给 Perl 脚本中的同名变量。

其他的都是正确的,因为您“来源”的任何 shell 脚本都将位于子 shell 中。我想我可以使用“sh -x cmd”至少让 shell 显示设置的变量。

这是我写的:

use strict;  use warnings;

our $DATE;

my $sh_script = "./test1.sh";

my $fh;
open($fh, "sh -x '$sh_script' 2>&1 1>/dev/null |") or die "open: $!";
foreach my $line (<$fh>) {
    my ($name, $val);
    if ($line =~ /^\+ (\w+)='(.+)'$/) {  # Parse "+ DATE='/bin/date;'
        $name = $1;
        ($val = $2) =~ s{'\\''}{'}g;  # handle escaped single-quotes (eg. "+ VAR='one'\''two'")
    } elsif ($line =~ /^\+ (\w+)=(\S+)$/) {  # Parse "+ DATE=/bin/date"
        $name = $1;
        $val = $2;
    } else {
        next;
    }
    print "Setting '$name' to '$val'\n" if (1);
    # NOTE: It'd be better to use something like "$shell_vars{$name} = $val",
    #  but this does what was asked (ie. $DATE = "/bin/date")...
    no strict 'refs';
    ${$name} = $val;    # assign to like-named variable in Perl
}
close($fh) or die "close: ", $! ? $! : "Exit status $?";

print "DATE: ", `$DATE` if defined($DATE);

你当然可以做更多的错误检查,但如果你只想捕获 shell 变量,这对我来说是个窍门。

【讨论】:

    【解决方案3】:

    你可以做一些简单的事情,像这样:

    system "source /path/to/shell_env.sh &&"
         . "/path/to/script.sh";
    

    请注意,这与以下不推荐的不同:

       system "source /path/to/shell_env.sh &&"
            . "/bin/sh /path/to/script.sh";
    

    【讨论】:

      【解决方案4】:

      是的,您现在可以使用 Env::Modify module 执行此操作。

      use Env::Modify qw(:ksh source);
      source("./test1.sh");     # env settings from test1.sh now available in Perl
      print `$ENV{DATE}`;       # print `/bin/date`;
      

      【讨论】:

        【解决方案5】:

        你不能在 Perl 5 中源 shell 文件。源代码实际上是在目标 shell 中运行 shell 文件中的命令;但是,打开和读取文件很简单:

        #!/usr/bin/perl
        
        use strict;
        use warnings;
        
        use Carp;
        
        sub source {
            my $file = shift;
            open my $fh, "<", $file
                or croak "could not open $file: $!";
        
            while (<$fh>) {
                chomp;
                #FIXME: this regex isn't quite good enough
                next unless my ($var, $value) = /\s*(\w+)=([^#]+)/;
                $ENV{$var} = $value;
            }
        }
        
        source "./test1.sh";
        
        print "$ENV{DATE}\n";
        

        【讨论】:

          【解决方案6】:

          嗯..下面是作弊吗?

          #!/bin/sh
          . ./test1.sh # source the test script
          echo Bash says $DATE
          export DATE;      # KEY to have the below Perl bit see $ENV{DATE}
          perl <<'ENDPERL';
              print "Perl says $ENV{DATE}\n";
          ENDPERL
          

          问题是获取 sh 文件可能会做任何事情,而不仅仅是将值 X 分配给变量 Y...

          【讨论】:

            【解决方案7】:

            我在一个项目中满足了 OP 的迫切需求,我需要通过采购一个定义环境的 shell 脚本来配置一个 Perl 脚本(它可以是任何语言)。

            我个人很少将采购用于配置和环境设置之外的任何其他事情(我知道采购的唯一其他充分理由是在 shell 脚本中导入函数,但我可能会错过一些创造性的用途)。

            我的解决方案是从启动器脚本(在 shell 中)获取配置脚本,然后在同一启动器脚本中exec Perl 脚本(用 Perl 脚本有效地替换启动器脚本,从而避免创建子进程)。

            # configuration_script.sh
            export MY_ENV_VAR1=value1
            export MY_ENV_VAR2=value2
            
            # launcher_script.sh
            . configuration_script.sh # source the configuration
            exec /path/to/main_script.pl "$@" # could be any other language here (Python, Tcl, Ruby, C, Java...)
            

            “$@”允许将命令行参数从启动器脚本传递到主脚本。

            然后由主脚本作者来检索环境(例如,在 Perl 中使用 $ENV{MY_ENV_VAR1})。

            【讨论】: