user2063351
user2063351

Reputation: 553

How to use the Unix/AIX find command with a pipe in Perl?

I'm trying to use the Unix/AIX find command piped to the head command to return the first file in a directory and assign it to a variable. However, all of my attempts have resulted in the all the files that find returns being assigned to the variable without the head command being applied.

Here's are my three attempts:

Attempt 1: 
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names | head -n1`;
Attempt 2: 
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names '|' head -n1`;
Attempt 3:
    $first_file = `/usr/bin/find $my_path -type f -name $potential_file_names \\| head -n1`;

The $potential_file_names variable is a string with wildcard characters to return any file in the directory that's in the format "fileXXX.txt" where 'XXX' is a three digit number.

$potential_file_names = 'file???.txt';

The first attempt doesn't work because Perl appears to take exception to the pipe as it returns error, "sh[2]: 0403-057.

First attempt output:

file001.txt
file002.txt
file003.txt
file004.txt
file005.txt

The second and third attempts also fail. The error for them is, "sh[2]: |: not found."

The output for the second and third attempts is the same as the first attempt.

Is it possible to use the find command piped to head to return the first file in the directory I'm searching (in my case, "file001.txt"?

Update I should mention that the file names may not start with 001, so I'll need the oldest file. The files are created sequentially, so grabbing the first file using find and piping to head -n1 works from the command line outside the script. It needs to be the oldest/first file because I'll be deleting files using a loop later in the script and this needs to find the oldest/first file for each iteration.

Thanks.

Upvotes: 1

Views: 979

Answers (3)

alexmac
alexmac

Reputation: 239

Okay, some of the answers create a dogs breakfast for follow on coders but do point in the correct direction, with the module 'use File::Find;'

Sample of how I use it. find (\&wanted, $directory); # start searching the path

sub wanted {
    my $file = $File::Find::name;
    if  (-d $file ) {
      $directoryMap{$file} = $file;
      return;
    }
    if (-z $file) {
       $zeroHash{$file} = 1;
       return;
    }
    if ($file =~                 /(AAF|MXF|NSV|Ogg|RM|SVI|SMI|WMV)$/i) {
       my $size = -s $file;
       if ($size) {
          $hashmap{$file} = $size;
          return;
       }
       else {
         $rejectMap{$file} = 1;
       return;
    }
  }
  else {
        $rejectMap{$file} = 1;
        return;
  }
 }

I use this to look for specific files with a specific extension and then I stuff them into a hash - the whole code an be found in my github in my Perl Diretory (https://github.com/alexmac131/mediaData). you can change the wanted to something useful for you.

Upvotes: 1

ThisSuitIsBlackNot
ThisSuitIsBlackNot

Reputation: 24073

Avoid using system and backticks when there are pure Perl equivalents; your code will be more portable and you won't have to worry about nasty shell quoting issues.

If you don't care about subdirectories, you can use readdir to get a list of files inside a particular directory:

#!/usr/bin/perl

use strict;
use warnings;

my $dir = 'foo';
opendir my $dh, $dir or die $!;

my @files = sort { -M "$dir/$b" <=> -M "$dir/$a" }
            grep { /^file\d{3}\.txt$/ && -f "$dir/$_" } readdir $dh;

closedir $dh;

print $files[0];

This prints the name of the file with the oldest modified date, although you could certainly use another file test instead.


If you also want to search inside subdirectories, you can use File::Find, which is a core module:

use File::Find;
use File::Spec;

my @files;
my $dir = 'foo';
find(sub { push @files, $File::Find::name if /^file\d{3}\.txt$/ and -f $_; }, $dir);

my @sorted = sort { -M $b <=> -M $a } @files;

print $sorted[0];

This prints the path to the file with the oldest modified date.

Upvotes: 2

Lawton
Lawton

Reputation: 51

Try something like this:

    open EXE, qq{/usr/bin/find $my_path -type f -name $potential_file_names | head -n1}
                    or die qq{Error running command $!};
    my $file = <EXE>;
    close(EXE);

Upvotes: 1

Related Questions