Sproggit
Sproggit

Reputation: 71

Cannot get the size of a file from its Directory Listing

I am currently trying to get the sizes of all the files in a directory listing (ignoring any sub-directories). I am using the opendir and readdir operations, and for each file I output the name and the size into a file. The File name is correctly output but not the size. I have tried this using the -s operator and the stat built-in function but with both I get the warning that the value is uninitialized.

My code is:

   #!/usr/bin/perl

    use strict;
    use warnings;

    my $dir = $ARGV[0];

    opendir(DIR, $dir) or die "Could not open directory '$dir' $!";

    my $filename = 'FileSize.txt';
    open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";

    while (my $file = readdir(DIR)) {

        # Ignore Sub-Directories
        next unless (-f "$dir/$file");
        my $size = -s $file;
        print $fh "$file"," ","$size\n";

    }

    closedir(DIR);
    exit 0;

I run the command from within the top level directory itself, including the name of the Sub-directory to be scanned, and get the following error, one for every file in the sub-directory that is processed

C:\Users\lafarnum\Documents>perl FileComp.pl DiskImage
Use of uninitialized value $size in concatenation (.) or string at 
FileComp.pl line 18.

Consequently, the file names are correctly output to the output file, but not the file sizes. The output file looks like this

BuildState.txt
data1.cab 
data1.hdr 
data2.cab 
ISSetup.dll 
layout.bin 
README.doc 
setup.bmp
setup.exe 
setup.ini 
setup.inx 
setup.iss 
vcredist_x86.exe 
_Setup.dll 

I think this has something to do with the way I am retrieving the file variable from readdir. All the examples of using the -s operator and the stat built-in function have been when users had hard coded the names of the files, not fetched them using readdir. I am new to using Perl, so apologies if I am making a basic error.

Upvotes: 1

Views: 326

Answers (2)

Grinnz
Grinnz

Reputation: 9231

(as pointed out by @tinita) The file test operators require a relative or absolute path to the file, while readdir will return only the basename of the file, so you need to concatenate the directory you're iterating with the basename to get the file path.

my $size = -s "$dir/$file";

For fun, here's how this script might look using Path::Tiny:

use strict;
use warnings;
use Path::Tiny;

my $dir = $ARGV[0];

my $fh = path('FileSize.txt')->openw;

foreach my $file (grep { -f } path($dir)->children) {
    my $basename = $file->basename;
    my $size = -s $file;
    print $fh "$basename $size\n";
}

Upvotes: 2

stack0114106
stack0114106

Reputation: 8811

Something like the below one liner would work..

/usr/libexec> \ls -1 | perl -ne '  while (<>) {chop($_); $size= -s "$_"; print "$size, $_\n" if not -d $_ } '
96168, gam_server
18808, gnupg-pcsc-wrapper
52232, gpg2keys_curl
61120, gpg2keys_finger
60888, gpg2keys_hkp
66432, gpg2keys_ldap
100344, gpg-check-pattern
85616, gpg-preset-passphrase
210416, gpg-protect-tool
21096, hald-addon-acpi
22352, hald-addon-generic-backlight
24136, hald-addon-hid-ups
17328, hald-addon-imac-backlight
31448, hald-addon-input
22776, hald-addon-ipw-killswitch
26224, hald-addon-leds
22384, hald-addon-macbook-backlight
22672, hald-addon-macbookpro-backlight

Upvotes: 0

Related Questions