我正在尝试source
来自Perl脚本(script.pl)的脚本。
system ("source /some/generic/script");
请注意,此通用脚本可以是shell,python或任何其他脚本。此外,我无法将此通用脚本中的逻辑复制到我的Perl脚本中。我尝试用{`,system
和exec
替换qx//
。每次我收到以下错误:
不能exec“source”:在script.pl第18行没有这样的文件或目录。
我在互联网上遇到过很多论坛,讨论了解决这个问题的各种原因。但他们都没有提供解决方案。有没有办法从Perl脚本运行/执行source
命令?
答案 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`;
或类似的。