如何从perl脚本运行“source”命令(Linux)?

时间:2015-11-18 13:38:15

标签: linux bash perl shell

我正在尝试source来自Perl脚本(script.pl)的脚本。

system ("source /some/generic/script");

请注意,此通用脚本可以是shell,python或任何其他脚本。此外,我无法将此通用脚本中的逻辑复制到我的Perl脚本中。我尝试用{`,systemexec替换qx//。每次我收到以下错误:

不能exec“source”:在script.pl第18行没有这样的文件或目录。

我在互联网上遇到过很多论坛,讨论了解决这个问题的各种原因。但他们都没有提供解决方案。有没有办法从Perl脚本运行/执行source命令?

3 个答案:

答案 0 :(得分:5)

在bash等中,source是内置的,意味着读取此文件,并在本地解释(有点像#include)。

在这个没有意义的上下文中 - 您需要从命令中删除source并在shell脚本的开头有一个shebang(#!)行告诉系统哪个shell为用于执行该脚本,或者您需要明确告诉system使用哪个shell,例如

system "/bin/sh", "/some/generic/script";

[没有评论在这种情况下是否真的适合使用system

答案 1 :(得分:2)

这里发生了一些事情。首先,子进程不能改变其父进程的环境。那个 source 只会在它的进程存在时持续存在。

这是一个设置和导出环境变量的简短程序。

#!/bin/sh
echo "PID" $$
export HERE_I_AM="JH";

运行文件不会导出变量。该文件在其自己的进程中运行。 set_stuff.sh 和 shell 中的进程 ID ($$) 不同:

$ chmod 755 set_stuff.sh
$ ./set_stuff.sh
PID 92799
$ echo $$
92077    
$ echo $HERE_I_AM       # empty

source 是不同的。它读取文件并在 shell 中对其进行评估。 set_stuff.sh 和 shell 中的进程 ID 是相同的,因此该文件实际上影响了它自己的进程:

$ unset HERE_I_AM       # start over
$ source set_stuff.sh
PID 92077
$ echo $$
92077
$ echo $HERE_I_AM
JH

现在开始介绍 Perl。调用 system 会创建一个子进程(在某处有一个 exec),因此它不会影响 Perl 进程。

$ perl -lwe 'system( "source set_stuff.sh;  echo \$HERE_I_AM" );
      print "From Perl ($$): $ENV{HERE_I_AM}"'
PID 92989
JH
Use of uninitialized value in concatenation (.) or string at -e line 1.
From Perl (92988):

奇怪的是,即使您的版本没有,这也有效。我认为不同之处在于这里没有特殊的 shell 元字符,所以它尝试执行程序目录,跳过它只是用于我更复杂的字符串的 shell:

$ perl -lwe 'system( "source set_stuff.sh" ); print $ENV{HERE_I_AM}'
Can't exec "source": No such file or directory at -e line 1.
Use of uninitialized value in print at -e line 1.

但是,在这种情况下您不需要单个字符串。列表形式更安全,但 source 不是任何可以执行的文件:

$ which source    # nothing
$ perl -lwe 'system( "source", "set_stuff.sh" ); print "From Perl ($$): $ENV{HERE_I_AM}"'
Can't exec "source": No such file or directory at -e line 1.
Use of uninitialized value in concatenation (.) or string at -e line 1.
From Perl (93766):

也就是说,您可以调用 source,但是作为调用 shell 的东西。

回到你的问题。有多种方法可以解决这个问题,但我们需要获得程序的输出。使用反引号代替 system。这是一个双引号上下文,所以我需要保护一些我想作为 shell 命令的一部分传递的文字 $

$ perl -lwe 'my $o = `echo \$\$ && source set_stuff.sh && echo \$HERE_I_AM`; print "$o\nFrom Perl ($$): $ENV{HERE_I_AM}"'
Use of uninitialized value in concatenation (.) or string at -e line 1.
93919
From Shell PID 93919
JH

From Perl (93918):

在反引号内,你会得到你喜欢的。 shell 程序可以看到该变量。一旦回到 Perl,它就不能了。但是,我现在有输出。让我们变得更花哨。摆脱 PID 的东西,因为我现在不需要看到它:

#!/bin/sh
export HERE_I_AM="JH";

并且 shell 命令创建一些具有名称和值的输出:

$ perl -lwe 'my $o = `source set_stuff.sh && echo HERE_I_AM=\$HERE_I_AM`; print $o'
HERE_I_AM=JH

我可以解析该输出并在 Perl 中设置变量。现在Perl已经导入了shell程序的部分环境:

$ perl -lwe 'my $o = `source set_stuff.sh && echo HERE_I_AM=\$HERE_I_AM`; for(split/\R/,$o){ my($k,$v)=split/=/; $ENV{$k}=$v }; print "From Perl: $ENV{HERE_I_AM}"'
From Perl: JH

不过,让我们获取整个环境。 env 以我刚刚处理的方式输出每个值:

$ perl -lwe 'my $o = `source set_stuff.sh && env | sort`; print $o'
...
DISPLAY=:0
EC2_PATH=/usr/local/ec2/ec2-api-tools
EDITOR=/usr/bin/vi
...

我在 shell 中设置了几百个变量,我不想暴露其中的大部分。这些都是Perl进程设置的,所以我可以暂时清除%ENV

$ perl -lwe 'local %ENV=(); my $o = `source set_stuff.sh && env | sort`; print $o'
HERE_I_AM=JH
PWD=/Users/brian/Desktop/test
SHLVL=1
_=/usr/bin/env

将其与后期处理代码放在一起,您就可以将该信息传递回父级。

顺便说一下,这类似于将变量传递回父 shell 进程的方式。由于该输出已经是 shell 能够理解的内容,因此您可以使用 shell's eval 而不是解析它。

答案 2 :(得分:1)

你不能。 source是一个shell函数,可以导入'该脚本的内容进入当前环境。它不是可执行文件。

你可以通过自己动手来复制它的一些功能 - 运行或解析你所采购的任何东西'并捕获结果:

 print `. file_to_source; echo $somevar`;

或类似的。