Perl"do",相对路径以"."开头.要么 ".."

Gre*_*edy 3 perl perldoc perl5 perl-core

我正在尝试使用Perl的do EXPR函数作为穷人的配置解析器,使用第二个.pl文件,它只返回一个列表作为配置信息.(我认为这可能是理想的用途do,尤其是因为我可以do or die在我的代码中写" ".这是一个例子:

main.pl

# Go read the config file
my %config = do './config.pl';

# do something with it
$web_object->login($config{username}, $config{password});
Run Code Online (Sandbox Code Playgroud)

config.pl

# Configuration file for main script
(
  username => "username",
  password => "none_of_your_business",
  favorite_color => "0x0000FF",
);
Run Code Online (Sandbox Code Playgroud)

阅读Perldocdo提供了很多关于相对路径的有用建议 - 搜索@INC和修改%INC,关于5.26不搜索"."的特殊警告.更多,等等.但它也有这些位:

#加载确切的指定文件(./和../ special-cased) ...


使用do与相对路径(./和../除外),如...

然后它实际上从来没有麻烦解释"./"或"../"的特殊情况路径处理 - 一个重要的遗漏!

所以我的问题是" 当你真正发生了什么"时的所有变化do './file.pl';?例如...

  • 虽然从@INC中删除了CWD,但这种语法是否仍然适用于5.26?
  • 从哪个角度看是"./":Perl二进制文件,执行的Perl脚本,来自用户shell的CWD,还是别的东西?
  • 是否存在安全隐患?
  • 这比修改@INC和使用基本文件名更好还是更差?

任何见解都表示赞赏.

Sob*_*que 5

好吧,所以 - 首先,我不确定你config.pl的确是正确的方法 - 它不perl适合初学者,因为它不能编译.无论哪种方式,尝试评估"解析配置"的东西通常不是一个很好的计划 - 它很容易出现令人不快的故障和安全漏洞,因此应该在需要时保留.

我敦促你以不同方式做到:

将其写为模块

像这样的东西:

package MyConfig;

# Configuration file for main script
our %config = (
   username       => "username",
   password       => "none_of_your_business",
   favorite_color => "0x0000FF",
);
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的主脚本中:

use MyConfig; #note - the file needs to be the same name, and in @INC
Run Code Online (Sandbox Code Playgroud)

并将其访问为:

print $MyConfig::config{username},"\n"; 
Run Code Online (Sandbox Code Playgroud)

如果你不能把它放在现有的@INC- 可能有你不能的原因,FindBin让你使用相对于你的脚本位置的路径:

use FindBin; 
use lib "$FindBin::Bin"; 
use MyConfig;
Run Code Online (Sandbox Code Playgroud)

将您的'config'写为定义的可解析格式,而不是可执行代码.

YAML

YAML 对于配置文件非常可靠,特别是:

use YAML::XS;

open ( my $config_file, '<', 'config.yml' ) or die $!; 
my $config = Load ( do { local $/; <$config_file> });

print $config -> {username};
Run Code Online (Sandbox Code Playgroud)

你的配置文件看起来像:

username: "username"
password: "password_here"
favourite_color: "green"
air_speed_of_unladen_swallow: "african_or_european?"
Run Code Online (Sandbox Code Playgroud)

(YAML也支持多维数据结构,数组等.但您似乎并不需要这些.)

JSON

JSON 基于看起来大致相同,只是输入是:

{
  "username": "username",
  "password": "password_here",
  "favourite_color": "green",
  "air_speed_of_unladen_swallow": "african_or_european?"
}
Run Code Online (Sandbox Code Playgroud)

你读它:

use JSON;
open ( my $config_file, '<', 'config.json' ) or die $!; 
my $config = from_json ( do { local $/; <$config_file> });
Run Code Online (Sandbox Code Playgroud)

使用配置的相对路径:

你根本不用担心@INC.你可以简单地使用基于相对路径...但更好的选择是不要那样做,FindBin而是使用- 这可以让你指定"相对于我的脚本路径"而且更加健壮.

 use FindBin;
 open ( my $config_file, '<', "$FindBin::Bin/config.yml" ) or die $!; 
Run Code Online (Sandbox Code Playgroud)

然后你就会知道你正在读取与你的脚本在同一目录中的那个,无论它从哪里被调用.

具体问题:

从哪个角度看是"./":Perl二进制文件,执行的Perl脚本,来自用户shell的CWD,还是别的东西?

当前工作目录向下传递进程.默认情况下是用户的shell,除非perl脚本执行了chdir

是否存在安全隐患?

任何时候你'评估'某些东西就好像它是可执行代码(并且EXPR可以),存在安全风险.它可能不是很大,因为脚本将以用户身份运行,并且用户是可以篡改的人CWD.核心风险是:

  • 用户位于"不同"的目录中,其他人为其运行了恶意内容.(例如,想象'config.pl'就rm -rf /*在其中).也许有一个'config.pl' /tmp,他们意外地"跑"了?
    • 你正在做的事情eval有一个错字,并以时髦和意想不到的方式打破脚本.(例如,它可能会$[以很难调试的方式重新定义和混淆程序逻辑)
  • 脚本在特权上下文中执行任何操作.这似乎并非如此,但请参阅前一点并想象您是否是root其他特权用户.

这比修改@INC和使用基本文件名更好还是更差?

更糟糕的IMO.实际上只是根本不修改@INC,并使用完整路径,或使用相对的路径FindBin.eval当没有必要时,不要做事情.