1

When initially checking if ARGV[0] is a file or directory, it worked fine with accurate results. Then further down into sub files I try it again and it doesnt return anything. This may seem like a small silly question but Im a student and help on programming on the weekends is scarce. Sometimes a new set of eyes can help.Thanks in advance.

#!/usr/bin/perl -w

my %hash;
my $args = @ARGV;

my $dh = $ARGV[0];

if ( -f $dh ) {
    words($dh);

} elsif ( -d $dh ) {
    files($dh);
}

sub words {
    open( my $file, '<', $_[0] ) or die 'cant open file';
    while ( my $line = <$file> ) {
        chomp $line;
        @words = split( /\s+/, $line );
        foreach $word (@words) {
            $word =~ tr/A-Z/a-z/;
            $hash{$word}++;
        }
    }

    foreach $key ( keys %hash ) {
        print $key. " " . $hash{$key} . "\n";
    }
}

sub files {
    opendir( DH, $_[0] );
    my @paths = grep !/^\./, readdir(DH);
    closedir(DH);
    foreach (@paths) {
        if ( -f $_ ) {
            print $_. "\n";
        }
    }
}
Miller
  • 34,962
  • 4
  • 39
  • 60
  • Welcome to Perl and SO. Please include [`use strict;`](http://perldoc.perl.org/strict.html) and [`use warnings;`](http://perldoc.perl.org/warnings.html) at the top of EVERY perl script. This is the #1 thing that you need to do to both learn and be a good programmer in Perl. – Miller Oct 11 '14 at 21:14

2 Answers2

3

You're missing path to your file,

if (-f "$_[0]/$_") ..

or to make it less obscure,

sub files{
  my ($path) = @_;

  opendir(my $DH, $path);
  my @paths = grep !/^\./, readdir($DH);
  closedir($DH);

  foreach (@paths) {
    if (-f "$path/$_") {
       print "$_\n";
    }
  }
}
mpapec
  • 50,217
  • 8
  • 67
  • 127
  • 1
    This worked perfectly ! Thank you. I knew it was something minor but I dont know enough about perl to see it. – user3491205 Oct 11 '14 at 20:42
1

As has already been stated, the return values of readdir contain just the basename. Therefore, to do file tests, you must either chdir or include the path info explicitly.

if (-f "$_[0]/$_") {

One alternative solution is to use Path::Class or some similar module for doing Cross-platform path specification manipulation.

The following is your script rewritten using this module:

use strict;
use warnings;

use Path::Class;

my $path = shift // die "Usage: $0 <Dir or File>\n";

words($path) if -f $path;
files($path) if -d $path;

sub words {
    my $file = file(shift);

    my %count;
    $count{ lc($_) }++ for split ' ', $file->slurp;

    for my $key ( keys %count ) {
        printf "%s %s\n", $key, $count{$key};
    }
}

sub files {
    my $dir = dir(shift);

    for ( $dir->children ) {
        next if $_->is_dir;
        print "$_\n", $_->basename;
    }
}
Miller
  • 34,962
  • 4
  • 39
  • 60