Perl - Can't use string ("html") as an ARRAY ref while "strict refs"
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Perl - Can't use string ("html") as an ARRAY ref while "strict refs"
The below snippet works fine until I use strict. Then it dies with the following error:
Quote:
Can't use string ("html") as an ARRAY ref while "strict refs" in use at ./filetest3 line 18.
I want to create @lists based on the $scalars in @type. However, "my @$ext = ()"; and push (@$ext, @files); do not play nice with strict. How do I get around this?
Quote:
#!/usr/bin/perl -w
system clear;
use strict;
use warnings;
use File::List;
my @type = ('html', 'mp3', 'txt');
my @files;
my $ext;
my $search;
my $file;
my $path;
If I understand what I'm looking at (and I'm not sure I do), you want to create an array of files for each extension. Since the module produces an array reference, you can easily put each of those into an array and have an array of arrays. Each array reference in the main array will have a list with all the files found with that extension. This should do what you want:
Code:
#!/usr/bin/perl
use strict;
use warnings;
use File::List;
my @extensions = ('html', 'mp3', 'txt');
my @files_by_extension;
print "Enter path: ";
chomp(my $path = <STDIN>);
my $search = new File::List($path);
foreach my $ext (@extensions) {
push @files_by_extension, $search->find("\.$ext\$");
}
use Data::Dumper;
print Dumper @files_by_extension;
Can anyone tell me why what I was doing fails only when using strict?
Because you're trying to use a variable name, $ext, to create a variable name, @$ext. This is a use of symbolic references, and it's one of the main things that strict disallows.
That is the jist of what I wanted.... tho I was trying to make the lists / arrays separate.
I've never used the File::List module before, and I'm not entirely nuts about its API. Here's how I might produce separate arrays using File::Find:
Code:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my $html = 'html';
my $mp3 = 'mp3';
my $txt = 'txt';
my (@htmls, @mp3s, @txts);
print "Give me the path: ";
chomp(my $path = <STDIN>);
find(\&insert_em, $path);
sub insert_em {
return if -d $_;
if ($_ =~ /$html$/) {
push @htmls, $File::Find::name;
return;
}
if ($_ =~ /$mp3$/) {
push @mp3s, $File::Find::name;
return;
}
if ($_ =~ /$txt$/) {
push @txts, $File::Find::name;
return;
}
}
use Data::Dumper;
print Dumper \@htmls, \@mp3s, \@txts;
In some ways, it feels wrong to hard-code the names that way, but if you know that those are the three types of files you're looking for, I don't see too much harm in it. In any case, it saves you from symbolic references.
Last edited by Telemachos; 08-08-2009 at 09:53 PM.
I've never used the File::List module before, and I'm not entirely nuts about its API. Here's how I might produce separate arrays using File::Find:
Code:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my $html = 'html';
my $mp3 = 'mp3';
my $txt = 'txt';
my (@htmls, @mp3s, @txts);
print "Give me the path: ";
chomp(my $path = <STDIN>);
find(\&insert_em, $path);
sub insert_em {
return if -d $_;
if ($_ =~ /$html$/) {
push @htmls, $File::Find::name;
return;
}
if ($_ =~ /$mp3$/) {
push @mp3s, $File::Find::name;
return;
}
if ($_ =~ /$txt$/) {
push @txts, $File::Find::name;
return;
}
}
use Data::Dumper;
print Dumper \@htmls, \@mp3s, \@txts;
In some ways, it feels wrong to hard-code the names that way, but if you know that those are the three types of files you're looking for, I don't see too much harm in it. In any case, it saves you from symbolic references.
Actually, this is not the complete script...... just a bit. I will be using STDIN to populate an array to hold what ever extensions need to be found. That is why I want to create several arrays based on the content of the extensions array.
Quote:
Because you're trying to use a variable name, $ext, to create a variable name, @$ext. This is a use of symbolic references, and it's one of the main things that strict disallows.
I have not read the link yet (though I will for sure) but I must say that I can think of many times when creating variables with symbolic references would be useful. Not being able to seems to remove alot of flexibility.
Quote:
You can actually do this in Perl (use a variable as a variable name), but it's a terrible idea.
Are you saying I can do it and still use strict? If so..... please tell me how.
My best solution if I must use variables with symbolic references may be this I guess... ?
Quote:
As you can see, the strict module imposes a very rigid environment for developing applications. But, that's a very nice and powerful feature, because it helps us track down a variety of bugs. In addition, the module allows for great flexibility as well. For example, if we know that a certain piece of code works fine, but will fail under strict, we can turn certain restrictions off, like so:
## code that passes strict
...
{
no strict; ## or no strict "vars";
## code that will not pass strict
}
All code within the block, delimited by braces, will have no restrictions.
Are you saying I can do it and still use strict? If so..... please tell me how.
No, sorry if I was unclear. I meant that you can do it in Perl if you don't use strict or you temporarily disable it (as you figured out yourself). You can't use symbolic references and strict at the same time, as far as I know.
Quote:
Originally Posted by OldGaf
I have not read the link yet (though I will for sure) but I must say that I can think of many times when creating variables with symbolic references would be useful. Not being able to seems to remove alot of flexibility.
This seems to be everyone's first reaction. All I can say is that I never use them, and I find I can do whatever I want in other ways.
Let me take your example for one more spin. You say that you will use STDIN to gather a list of extensions and then you want to populate arrays containing files ending in those extensions. My first thought is a hash of arrays. What I would do is take the items given on STDIN and make those hash keys. The value of each of those would be an anonymous array reference. That way, I could refer to precisely which extension I wanted, whenever I wanted, because the hash key allows specific lookup.
Here's a short implementation, reusing my File::Find code from above.
Code:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my %files_by_ext;
print "Give me the path: ";
chomp(my $path = <STDIN>);
print "Give me the extensions to search for, separated by spaces: ";
chomp(my @extensions = split /\s+/, <STDIN>);
@files_by_ext{ @extensions } = [];
find(\&insert_em, $path);
use Data::Dumper;
print Dumper \%files_by_ext;
sub insert_em {
return if -d $_;
for my $ext (keys %files_by_ext) {
if ($_ =~ /$ext$/) {
push @{ $files_by_ext{$ext} }, $File::Find::name;
return;
}
}
}
Sample output:
Code:
telemachus ~ $ perl file_list
Give me the path: /home/telemachus/test
Give me a list of extensions to search for, separated by spaces: mp3 html txt
$VAR1 = {
'mp3' => [
'/home/telemachus/test/foo.mp3',
'/home/telemachus/test/further/bar.mp3',
'/home/telemachus/test/further/down/buzz.mp3'
],
'html' => [
'/home/telemachus/test/foo.html',
'/home/telemachus/test/further/bar.html',
'/home/telemachus/test/further/down/buzz.html'
],
'txt' => [
'/home/telemachus/test/foo.txt',
'/home/telemachus/test/further/bar.txt',
'/home/telemachus/test/further/down/buzz.txt'
]
};
To OP - believe me (after 15+ years of experience with Perl) - you practically never need variables with dynamically created variable names, since you can always write
Code:
my %vars_with_dynamic_names;
...
$vars_with_dynamic_names{$some_funky_name} = foo;
...
$bar = $vars_with_dynamic_names{$some_funky_name};
;
even more practically never you need to work without
Code:
use strict;
- not using 'strict' is rarely needed in cases of obscure global namespace manipulation which happens in very core Perl modules - you (and even me, despite the 15+ years of experience with Perl) are quite far from it.
In simple English - if your code doesn't work with
Code:
use strict;
your code is guilty until proven innocent, and the latter almost never happens.
Let me take your example for one more spin. You say that you will use STDIN to gather a list of extensions and then you want to populate arrays containing files ending in those extensions. My first thought is a hash of arrays.
Absolutely correct, IMHO. Surprises me how many posters avoided coming to this conclusion.
--- rod.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.