LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-08-2009, 12:19 PM   #1
OldGaf
Member
 
Registered: Feb 2008
Posts: 47

Rep: Reputation: 15
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;

foreach $ext (@type) {

"my @$ext = ()";

}

print "Enter path:";
chomp($path = <STDIN>);

foreach $ext (@type) {
$search = new File::List("$path");
@files = @{ $search->find("\.$ext\$")};

push (@$ext, @files);

}

Last edited by OldGaf; 08-08-2009 at 12:21 PM. Reason: c
 
Old 08-08-2009, 04:54 PM   #2
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
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;
Sample output:

Code:
Enter path: /home/telemachus/test
$VAR1 = [
          '/home/telemachus/test/further/down/buzz.html',
          '/home/telemachus/test/further/bar.html',
          '/home/telemachus/test/foo.html'
        ];
$VAR2 = [
          '/home/telemachus/test/further/down/buzz.mp3',
          '/home/telemachus/test/further/bar.mp3',
          '/home/telemachus/test/foo.mp3'
        ];
$VAR3 = [
          '/home/telemachus/test/further/bar.txt',
          '/home/telemachus/test/further/down/buzz.txt',
          '/home/telemachus/test/foo.txt'
        ];
 
Old 08-08-2009, 05:36 PM   #3
OldGaf
Member
 
Registered: Feb 2008
Posts: 47

Original Poster
Rep: Reputation: 15
Thanks Telemachos.

That is the jist of what I wanted.... tho I was trying to make the lists / arrays separate.

Can anyone tell me why what I was doing fails only when using strict?
 
Old 08-08-2009, 05:59 PM   #4
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
Quote:
Originally Posted by OldGaf View Post
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.

See these two links:
http://perldoc.perl.org/strict.html
http://perldoc.perl.org/perlref.html...lic-references

You can actually do this in Perl (use a variable as a variable name), but it's a terrible idea. See here: http://perl.plover.com/varvarname.html

Last edited by Telemachos; 08-08-2009 at 06:01 PM.
 
Old 08-08-2009, 09:07 PM   #5
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
Quote:
Originally Posted by OldGaf View Post
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.
 
Old 08-09-2009, 08:28 AM   #6
OldGaf
Member
 
Registered: Feb 2008
Posts: 47

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by Telemachos View Post
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.
 
Old 08-09-2009, 09:06 AM   #7
OldGaf
Member
 
Registered: Feb 2008
Posts: 47

Original Poster
Rep: Reputation: 15
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.
Though I will not be entirely happy with it. :O(

Last edited by OldGaf; 08-09-2009 at 09:08 AM.
 
Old 08-09-2009, 10:27 AM   #8
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
Quote:
Originally Posted by OldGaf
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'
                   ]
        };
 
Old 08-09-2009, 10:52 AM   #9
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
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.
 
Old 08-11-2009, 11:14 AM   #10
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
Quote:
Originally Posted by Telemachos View Post
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.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
"Permission denied" and "recursive directory loop" when searching for string in files mack1e Linux - Newbie 5 06-12-2008 07:38 AM
How to convert "string" type to "char * " in c++ pranavojha Programming 18 06-05-2008 03:10 PM
net working eth0 eth1 wlan0 "no connection" "no LAN" "no wi-fi" Cayitano Linux - Newbie 5 12-09-2007 07:11 PM
Standard commands give "-bash: open: command not found" even in "su -" and "su root" mibo12 Linux - General 4 11-11-2007 10:18 PM
LXer: Displaying "MyComputer", "Trash", "Network Servers" Icons On A GNOME Desktop LXer Syndicated Linux News 0 04-02-2007 08:31 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:26 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration