Solved

Count how many files are in a directory

Posted on 2003-12-02
21
9,232 Views
Last Modified: 2007-12-19
I am looking for a perl script that can count the number of jpg files in a given directory. Can this be done? What does the script look like?
0
Comment
Question by:waffe
  • 7
  • 6
  • 5
  • +1
21 Comments
 
LVL 20

Expert Comment

by:jmcg
ID: 9861615
One way to do it:

chdir $dir
my @files = <*.jpg>;
print "There are ", scalar(@files), " jpg files in directory $dir\n";
0
 

Author Comment

by:waffe
ID: 9863290
Works great, but can you make it so @files only = the last photo in the directory. Right now it = all of the photos in the directory.
0
 
LVL 84

Assisted Solution

by:ozo
ozo earned 25 total points
ID: 9863909
$files = (<*.jpg>)[-1];  #if you mean last alphabeticly.
0
 

Author Comment

by:waffe
ID: 9864168
Sorry but that will not work because all of my jpg files are numbered starting with 1. So if I have 30 jpg then $files should = 30.jpg.
0
 
LVL 20

Accepted Solution

by:
jmcg earned 75 total points
ID: 9864292
Cross-reference: http:Q_20814726.html

In this other question, I showed how to sort the list by modification date.

To sort the filenames by their numerical content, we could do something like this:

chdir $dir;
my @images = glob "*.jpg";
my @images_sorted = map { $_->[1] }
        sort { $b->[0] <=> $a->[0] }
        map { /(\d+)/; [$1, $_] } @images;

If your filenames really are numbered the way you say, though, perl will do the numerical comparison on them without the extra step of extracting the numbers:

chdir $dir;
my @imagelist = sort { $b <=> $a } glob "*.jpg";

0
 

Author Comment

by:waffe
ID: 9864780
LOL - No double posting here...

Not working just yet. This is what I got.

My files are numbered like:
1.jpg, 2.jpg, 3.jpg, etc...

I have tried both scripts above and I get the same results as the first code you gave me. The array always equals all of the photos in my folder.

0
 
LVL 84

Expert Comment

by:ozo
ID: 9864866
Just take $imagelist[-1] if you want only the last one
0
 

Author Comment

by:waffe
ID: 9865137
When I use  $imagelist[-1] I always get 9.jpg if the dir had more then 9 files in it. If the dir had less the 9 files in it I get a correct output.
0
 
LVL 20

Expert Comment

by:jmcg
ID: 9865998
It worked for me, so I think we need to see some more details of your situation to know why it's not working for you: code of your script, list of actual filenames, etc.
0
 
LVL 1

Expert Comment

by:josephfluckiger
ID: 9866661
If 9.jpg is coming first it probably means that you are performing an ASCII comparison rather than a numerical one.

This might be because you are leaving out the "spaceship operator", the "<=>" which causes a numerical comparison. If you leave this out, the sort function by default performs an ASCII comparison which would result in "9.jpg" coming before  "10.jpg" (when reverse sorted). But jmcg's code should not have this problem as it is written.

for example I have files 1.jpg,2.jpg,3.jpg ... 30.jpg in a directory.
------------jmcg's solution causes 30.jpg to correctly come first-------------
chdir $dir;
my @images = glob "*.jpg";
my @images_sorted = map { $_->[1] }
        sort { $b->[0] <=> $a->[0] }
        map { /(\d+)/; [$1, $_] } @images;
-------------------------------------------------------------------------------------

-------------this code causes 9.jpg to incorrectly come first (notice the "gt")-------------------
chdir $dir;
my @images = glob "*.jpg";
my @images_sorted = map { $_->[1] }
        sort { $b->[0] gt $a->[0] }
        map { /(\d+)/; [$1, $_] } @images;
-------------------------------------------------------------------------------------

perhaps you are using some variation of the second.

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:waffe
ID: 9870547
Here is my perl script and my dir looks just like josephfluckiger's.

#!/usr/bin/perl -w

use CGI qw(:standard);
use strict;

my $galleryNum     = param('gallery');
my $dir                 = "/home/www/domain.com/data_base/gallery/gallery$galleryNum";

chdir $dir;
my @images = glob "*.jpg";
my @images_sorted = map { $_->[1] }
        sort { $b->[0] <=> $a->[0] }
        map { /(\d+)/; [$1, $_] } @images;


 print <<ENDHTML;

<HTML>
<HEAD>
<TITLE>Photos</TITLE>
</HEAD>
<BODY>
<BODY BGColor="000000">
<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
WIDTH="550" HEIGHT="450"  id="http://www.domain.com/data_base/gallery/gallery.swf">
<PARAM NAME=movie VALUE="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images[-1]&gallery=$galleryNum">
<PARAM NAME=quality VALUE=high>
<PARAM NAME=bgcolor VALUE=#000000>

<EMBED src="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images[-1]&gallery=$galleryNum" quality=high bgcolor=#000000 WIDTH="550" HEIGHT="450"
NAME="http://www.doamin.com/data_base/gallery/gallery.swf" ALIGN="" TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
</EMBED>
</OBJECT>
There are ", scalar($images[-1]), " jpg files in directory $dir\n
</BODY>
</HTML>
ENDHTML
0
 
LVL 1

Assisted Solution

by:josephfluckiger
josephfluckiger earned 50 total points
ID: 9870644

I think I see the problem. You are using the @images array instead of the @images_sorted array in the line:

There are ", scalar($images[-1]), " jpg files in directory $dir\n

0
 
LVL 1

Expert Comment

by:josephfluckiger
ID: 9870671
and more importantly you also use it in the two lines:
------------------------currently incorrect------------------
<PARAM NAME=movie VALUE="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images[-1]&gallery=$galleryNum">
<EMBED src="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images[-1]&gallery=$galleryNum" quality=high bgcolor=#000000 WIDTH="550" HEIGHT="450"

------------------------corrected-----------------------------
<PARAM NAME=movie VALUE="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images_sorted[-1]&gallery=$galleryNum">
<EMBED src="http://www.domain.com/data_base/gallery/gallery.swf?jpgNum=$images_sorted[-1]&gallery=$galleryNum" quality=high bgcolor=#000000 WIDTH="550" HEIGHT="450"
0
 
LVL 20

Expert Comment

by:jmcg
ID: 9870725
And, since the array was sorted in reverse numerical order, the newest file is

$images_sorted[0]
0
 

Author Comment

by:waffe
ID: 9871955
That was it! My bad - right in front of my face and I missed it. I got to look alittle closer at the code you people give me. It has something to do with the exspressions, they are intimidateing. Side question - what is the best book out there for getting to know perl exspressions?
0
 
LVL 20

Expert Comment

by:jmcg
ID: 9872201
I first learned Perl from the Camel book (_Programming Perl_, Larry Wall et al, O'Reilly & Associates), but that was the first edition. The 2nd and 3rd editions strike me as being less suitable for learning from, but it's still an essential reference book.

This particular stack of map -- sort -- map is often known as a Schwartzian Transform. It _is_ a little intimidating at first. I think I was reading Randall Schwartz's articles on Perl for a year before I finally started to be able to make up my own devices based on this particular coding technique.
0
 
LVL 1

Expert Comment

by:josephfluckiger
ID: 9872261
Thanks for the points. They are my first official expert points!  (jmcg did most the hard work)

Here is an excerpt from Programming Perl, 3rd Edition on the sort function:

-------------------------
29.2.159 sort

sort USERSUB LIST
sort BLOCK LIST
sort LIST

This function sorts the LIST and returns the sorted list value. By default, it sorts in standard string comparison order (undefined values sort before defined null strings, which sort before everything else). When the use locale pragma is in effect, sort LIST sorts LIST according to the current collation locale.

USERSUB, if given, is the name of a subroutine that returns an integer less than, equal to, or greater than 0, depending on how the elements of the list are to be ordered. (The handy <=> and cmp operators can be used to perform three-way numeric and string comparisons.) If a USERSUB is given but that function is undefined, sort raises an exception.

In the interests of efficiency, the normal calling code for subroutines is bypassed, with the following effects: the subroutine may not be a recursive subroutine (nor may you exit the block or routine with a loop control operator), and the two elements to be compared are not passed into the subroutine via @_, but rather by temporarily setting the global variables $a and $b in the package in which the sort was compiled (see the examples that follow). The variables $a and $b are aliases to the real values, so don't modify them in the subroutine.

The comparison subroutine is required to behave. If it returns inconsistent results (sometimes saying $x[1] is less than $x[2] and sometimes saying the opposite, for example), the results are not well defined. (That's another reason you shouldn't modify $a and $b.)

USERSUB may be a scalar variable name (unsubscripted), in which case the value provides either a symbolic or a hard reference to the actual subroutine to use. (A symbolic name rather than a hard reference is allowed even when the use strict 'refs' pragma is in effect.) In place of a USERSUB, you can provide a BLOCK as an anonymous, inline sort subroutine.

To do an ordinary numeric sort, say this:

sub numerically { $a <=> $b }
@sortedbynumber = sort numerically 53,29,11,32,7;

To sort in descending order, you could simply apply reverse after the sort, or you could reverse the order of $a and $b in the sort routine:

@descending = reverse sort numerically 53,29,11,32,7;

sub reverse_numerically { $b <=> $a }
@descending = sort reverse_numerically 53,29,11,32,7;

To sort strings without regard to case, run $a and $b through lc before comparing:

@unsorted = qw/sparrow Ostrich LARK catbird blueJAY/;
@sorted = sort { lc($a) cmp lc($b) } @unsorted;

(Under Unicode, the use of lc for case canonicalization is vaguely preferred to the use of uc, since some languages differentiate titlecase from uppercase. But that doesn't matter for basic ASCII sorting, and if you're going to do Unicode sorting right, your canonicalization routines are going to be a lot fancier than lc.)

Sorting hashes by value is a common use of the sort function. For example, if a %sales_amount hash records department sales, doing a hash lookup in the sort routine allows the hash keys to be sorted according to their corresponding values:

# sort from highest to lowest department sales
sub bysales { $sales_amount{$b} <=> $sales_amount{$a} }

for $dept (sort bysales keys %sale_amount) {
    print "$dept => $sales_amount{$dept}\n";
}

You can perform additional levels of sorting by cascading multiple comparisons using the || or or operators. This works nicely because the comparison operators conveniently return 0 for equivalence, causing them to fall through to the next comparison. Here, the hash keys are sorted first by their associated sales amounts and then by the keys themselves (in case two or more departments have the same sales amount):

sub by_sales_then_dept {
    $sales_amount{$b} <=> $sales_amount{$a}
       ||
    $a cmp $b
}

for $dept (sort by_sales_then_dept keys %sale_amount) {
    print "$dept => $sales_amount{$dept}\n";
}
0
 

Author Comment

by:waffe
ID: 9872367
Thanks for the info! I feel a bit dizzy after that.) That opens about a hundred questions josephfluckiger. Here is one more if you don't mind.

Please explain where $a and $b come from in the sort comand. Are they apart of the sort object? I see it like this:
@images = glob "*.jpg" is $a
@images_sorted = map { $_->[1] is $b

Is the correct way of looking at it?
0
 
LVL 84

Expert Comment

by:ozo
ID: 9872408
perldoc -f sort
0
 
LVL 20

Expert Comment

by:jmcg
ID: 9872646
Regarding $a and $b:

No. The 'sort', 'map', and 'grep' commands are three perl functions that can take, as their second argument, a code block. For 'map' and 'grep', the $_ variable is used to pass in the "current" value of the array. For 'sort', two variables must be available in the comparison routine; these are $a and $b.

The structure of that formidable Schwartzian Transform is something like this:

@result = map UNDO_CODEBLOCK1 sort COMPARE map CODEBLOCK1 @array;

The COMPARE codeblock uses the $a and $b variables. The sort function calls the COMPARE block with pairs of elements from it's input array. The results from the COMPARE codeblock inform the sort function whether $a should be placed _before_ $b or _after_.

The purpose of CODEBLOCK1 is to process the input array into a data structure containing an easily manipulated sort key associated with some sort of handle or reference to the original data (it could copy the entire original data item into this data structure). The purpose of UNDO_CODEBLOCK1 is to take the array and essentially undo what CODEBLOCK1 did. It regurgitates th original data, but now in the order that was selected by 'sort'.
0
 
LVL 1

Expert Comment

by:josephfluckiger
ID: 9874706
Any sort routine is basically a serious of comparisons. For example if you were to manually take the list [2,3,1] and sort in accending order, you would say: (none of this is perl code, it's just an example)

2 < 3 ? yes, don't swap
   [current list: 2,3,1]
2 < 1 ? no, swap
   [current list: 1,3,2]
3 < 2 ? no, swap
   [current list: 1,2,3]


$a and $b are the variables that the sort command uses to make this comparison. I think you could say they are "part of the sort function". But the last part of your statement with the two equal signs, I think is incorrect.

0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Many time we need to work with multiple files all together. If its windows system then we can use some GUI based editor to accomplish our task. But what if you are on putty or have only CLI(Command Line Interface) as an option to  edit your files. I…
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now