Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Could someone tell me why the find command always go to the root directory but not the directory that is specified in $srceDir?

my $srceDir = "/mnt/SDrive/SV/Capture Data/";

my $find_cmd = 'find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15';

open(FIND_FILE, "$find_cmd |");
while(<FIND_FILE>){ 
    next if /^total/; # because we're only interested in real output
    print $_; 
}
share|improve this question
    
Better asked on stackoverflow.com , probably a duplicate... –  F. Hauri Feb 15 '13 at 18:09
    
That question was answered in your other question –  Stephane Chazelas Feb 15 '13 at 18:19
add comment

2 Answers

Because you use single quotes instead of double...

Perl doesn't interpolate variables enclosed in single quotes, so what you are doing is sending the string '$srceDir' to the shell which will normally be unset (blank) unless you have it set in your environment somewhere.

Try this:

my $find_cmd = "find $srceDir -type f -newermt 2013-02-14 ! -newermt 2013-02-15";

or better this:

my $find_cmd = sprintf
    'find "%s" -type f -newermt 2013-02-14 ! -newermt 2013-02-15',
    $srceDir;

... care about spaces while *find_cmd* would be executed under forked sh.

* Important remark *

As @vonbrand rightly comment: do offer a lot of libraries for ensuring communication between your programm and approx everything.

For file system operation find perl use the File library module File::Find, for wich a little utility exist: find2perl who will translate your commande line in a little perl script:

$ find2perl -type f -mtime -3 ! -mtime -2;
#! /usr/bin/perl -w
    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
        if 0; #$running_under_some_shell
use strict;
use File::Find ();

# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

sub wanted;

# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '.');
exit;

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);
    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -f _ &&
    (int(-M _) < 3) &&
    ! (int(-M _) < 2)
    && print("$name\n");
}

So your need could become something like this:

#! /usr/bin/perl -w

my $srceDir   = "/mnt/SDrive/SV/Capture Data/";
my $startDate = "2013-02-14";
my $endDate   = "2013-02-15";

use strict;
use File::Find ();
use POSIX qw|mktime|;

use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

my ($sDay,$eDay)=map {
    my ($year,$month,$day)=split("-",$_);
    (time()-mktime(0,0,0,$day,$month-1,$year-1900))/86400
} ($startDate,$endDate);

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);

    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
    -f _ &&
    (-M _ < $sDay) &&
    ! (-M _ < $eDay)
    && print("$name\n");
}
File::Find::find({wanted => \&wanted}, $srceDir );

The most advantage of doing this, instead of open $fh,"find ...|" is that this is very robust, you don't have to care about of characters present in filenames (like spaces, quotes, ampersand...).

share|improve this answer
    
wow, it works. thanks so much for your help :). –  oanh Feb 15 '13 at 19:28
1  
Great catch! But Perl has File::Find <perldoc.perl.org/File/Find.html>;, which allows you to integrate the functionality directly into the script. –  vonbrand Feb 15 '13 at 19:59
    
@oanh If this answer solved your problem, please remember to mark it as accepted and/or upvote it instead of posting a thank you comment. That is the way thanks are expressed on SE sites. –  terdon Feb 16 '13 at 0:28
    
Your logic about (int(-M _) < $sDay) is wrong unless you run your script at midnight (and even then, I suppose DST changes would mess things up). Note that Date::Parse is not one of the core perl modules (contrary to File::Find or POSIX (mktime) or now Time::Piece). By using find "%s" ..., you'll still have issues with filenames with double quote, backtick, dollar or backslash characters. –  Stephane Chazelas Feb 16 '13 at 19:33
add comment

If you give one string with shell meta characters (like space) for your command then it will be interpreted as a shell command line which means two things:

  1. An extra command needs to be executed (the shell to parse that command line) which is not very efficient. With some shell implementations, that even means an extra process.
  2. You need to escape special characters to the shell.

Best is to execute the command directly, that is by giving the list of arguments to the command to execute, instead of asking for a shell to split a command line to build that list of arguments.

Also, unless you use -print0, the output of find can't be post-processed safely because the records are separated with newline characters while newline is a perfectly valid character in a file name, so like I said in my answer to your similar question, you'd need to write it like:

my $srceDir = "/mnt/SDrive/SV/Capture Data";
my @find_cmd = ("find", $srceDir, "-type", "f", "-newermt", "14 Feb 2013", "-print0");

open FIND, "-|", @find_cmd;
$/ = "\0"; # set perl's record separator
while (<FIND>) {
  ...
}
close FIND or warn $! ?
  "Error closing find pipe: $!" :
  "find exited with non-zero exit status: $?";

(and BTW, find doesn't output total lines, you may be confusing with ls).

share|improve this answer
    
On what condition could close FIND fail? –  warl0ck Feb 16 '13 at 10:44
    
@warl0ck The close or warn $! ? "Error $!" : "Error, rc was: $?" ; statment is a clean, nice and safe way of closing command pipes, in order to permit debugging, for sample. (+1 for Stephane, just for this :). At all, for dealing with complex filenames and reducing fork calls, preferring to use standards libraries, like File::Find is a good practice! –  F. Hauri Feb 16 '13 at 16:36
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.