#perl
#perl
Вопрос:
У меня есть файл, содержащий данные, подобные приведенным ниже:
output.pl
{
"A" => {
"name" => "chetan",
"age" => "28",
},
"B" => {
"name" => "vivek",
"age" => "31",
},
};
По сути, это хэш, хранящийся в другом файле.
Как мне написать программу на perl, чтобы загрузить это как хэш в переменной?
Я пробовал что-то вроде этого:
use Data::Dumper;
use File::Slurp;
my %hash = read_file("output.pl");
print Dumper(keys(%hash));
Но я вижу, что там указано нечетное количество элементов, присвоенных хэшу.
Комментарии:
1. Я не уверен, какие методы лучше всего использовать, поэтому не буду отвечать. Однако простой способ сделать это есть
my $hash = do "output.pl"
.2. Кстати, вам, вероятно, следует,
print Dumper %hash
а неprint Dumper(keys(%hash))
.3. Вы также могли бы взглянуть на
Config::Hash
.4. Потому что, если он
output.pl
содержит что-то вродеsystem "rm -rf /"
, вам не понравится то, чтоdo "output.pl"
только что было сделано. Тогда как, если бы вы просто регулярно анализировали свой файл, это не было бы проблемой. Но еще раз, у меня нет какого-либо твердого мнения по этому вопросу, поэтому я просто подожду, пока другие люди поделятся своими мыслями5.
import
это не ключевое слово perl, которое вы хотелиuse
. Избегайте File::Slurp, File::Slurper лучше.
Ответ №1:
Вы можете загрузить такие данные с помощью функции do.
use strict;
use warnings;
my $file = './output.pl';
my $data = do $file;
# unfortunately 'do' error checking is very fragile
# there is no way to differentiate certain errors from the file returning false or undef
unless ($data) {
die "couldn't parse $file: $@" if $@;
die "couldn't do $file: $!" unless defined $data;
die "$file did not return data";
}
Это, конечно, приведет к запуску любого произвольного кода в файле, но обычно это не проблема, пока конфигурационный файл недоступен для записи кем-либо, кто не может также редактировать скрипт.
Некоторыми другими параметрами для конфигурационных файлов, которые не позволяют запускать произвольный код, могут быть JSON и Config::Tiny.
Обязательно используйте ./output.pl
и не output.pl
; без ведущего ./
do
функция будет выполнять поиск @INC
(который больше не содержит текущий каталог в версии 5.26 ), а не просто использовать текущий каталог.
Если вы хотите загрузить файл из того же каталога, что и текущий файл, а не из текущего рабочего каталога (как правило, более надежное решение), смотрите Dir::Self или Path::Tiny или аналогичный, с абсолютным путем, чтобы @INC
не выполнялся поиск.
use Dir::Self;
my $file = __DIR__ . '/output.pl';
use Path::Tiny;
my $file = path(__FILE__)->realpath->sibling('output.pl');
Ответ №2:
Я вижу как минимум две проблемы в вашем коде:
- вы пытаетесь присвоить содержимое файла хэшу (вместо его оценки)
- ваш файл содержит ссылку на хэш, а не сам хэш.
Это один из альтернативных способов загрузки и анализа содержимого файла:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
# replacement for loading external file - not relevant for solution
my $content;
{
local $/;
$content = <DATA>;
}
#print "${content}n";
my $hash = eval $content;
die "eval error: $@" if $@;
#print "${hash}n";
print Dumper($hash);
exit 0;
__DATA__
{
"A" => {
"name" => "chetan",
"age" => "28",
},
"B" => {
"name" => "vivek",
"age" => "31",
},
};
Тестовый запуск:
$ perl dummy.pl
$VAR1 = {
'A' => {
'name' => 'chetan',
'age' => '28'
},
'B' => {
'name' => 'vivek',
'age' => '31'
}
};
Ответ №3:
Как и выше с Slurp, в одной строке.
use File::Slurp ;
# no easy way to get current Mojolicious config, so this is a hack
my $config = eval (read_file( '/etc/smsmap/sms_map.conf'));